diff --git a/package.json b/package.json
index 83c0be28637d7770d56c752cdfc575c931757f40..f8efc40b9b5a28a1a73c674389ce9df4b7c89c7b 100644
--- a/package.json
+++ b/package.json
@@ -89,9 +89,6 @@
     "typescript": "^3.2.1",
     "vue-template-compiler": "^2.5.21"
   },
-  "gitHooks": {
-    "pre-commit": "lint-staged"
-  },
   "lint-staged": {
     "*.{js,vue}": [
       "vue-cli-service lint",
diff --git a/src/components/admin/AdminMenu.vue b/src/components/admin/AdminMenu.vue
index 4eef7bde0f133a355a1b695da746c93076d03550..4d4d1f7cb1d6435caf1e3f3875423df119541ac4 100644
--- a/src/components/admin/AdminMenu.vue
+++ b/src/components/admin/AdminMenu.vue
@@ -24,7 +24,7 @@
     </div>
     <va-modal
       v-model="confirmAction"
-      :message="$t('admin_menu.change_tag_confirmation', {action: $t(userOptions[activeTag] ? `tags.${activeTag}-neg` : `tags.${activeTag}`)})"
+      :message="$t('pleroma.admin_menu.change_tag_confirmation', {action: $t(userOptions[activeTag] ? `tags.${activeTag}-neg` : `tags.${activeTag}`)})"
       @ok="toggleTag(activeTag)"
       @cancel="this.activeTag = null"
     />
diff --git a/src/components/admin/UserActionsDropdown.vue b/src/components/admin/UserActionsDropdown.vue
index 90733384aaeb8995ff4d2bf4fe7bb844aeb70696..a263937ad90e18459e1cbe3a731336f27432ac7f 100644
--- a/src/components/admin/UserActionsDropdown.vue
+++ b/src/components/admin/UserActionsDropdown.vue
@@ -18,10 +18,10 @@
       <va-icon
         color="danger"
         @click.native="confirmDeleteAccount = true"
-        icon="ion-ios-trash-outline"
+        name="ion-ios-trash-outline"
         class="user-actions-panel__icon pa-2"
       />
-      <va-dropdown-popper
+      <va-dropdown
         position="left"
         :max-width="250"
         :maxHeight="150"
@@ -45,7 +45,7 @@
             />
           </div>
         </va-card>
-      </va-dropdown-popper>
+      </va-dropdown>
     </div>
     <va-modal
       v-model="confirmDeleteAccount"
diff --git a/src/components/auth/login/Login.vue b/src/components/auth/login/Login.vue
index d024fab31ec2800ed3c7a2ce353f384d6e0f03e3..5a05909f4a46cb7001b50c2c0524b87a6fc6c734 100644
--- a/src/components/auth/login/Login.vue
+++ b/src/components/auth/login/Login.vue
@@ -2,11 +2,11 @@
   <va-card class="login" title="To have an access to EPIC PLEROMA FE, please login">
     <form @submit.prevent="authorize">
       <va-icon-vuestic/>
-      <div class="va-row mb-4">
+      <div class="va-row">
         <va-input
           v-model="usernameAndInstance"
           type="email"
-          :label="$t('login-placeholder')"
+          :label="$t('pleroma.login-placeholder')"
           :error="!!error.length"
           :error-messages="[error]"
         />
@@ -15,7 +15,7 @@
         <va-input
           v-model="password"
           type="password"
-          :label="$t('password-placeholder')"
+          :label="$t('pleroma.password-placeholder')"
         />
       </div>
       <div class="va-row justify--center">
diff --git a/src/components/configSettings/ConfigSettingsForms.vue b/src/components/configSettings/ConfigSettingsForms.vue
new file mode 100644
index 0000000000000000000000000000000000000000..d16eb7ce99028e2e05b165f0bf329b5f52e52f26
--- /dev/null
+++ b/src/components/configSettings/ConfigSettingsForms.vue
@@ -0,0 +1,225 @@
+<template>
+<div>
+  <template v-for="tab in tabs">
+    <config-form
+      :key="tab.key"
+      v-model="config[tab.key]"
+      :title="tab.key"
+      :showTitle="showTabTitle(tab)"
+      v-if="showTab(tab)"
+    />
+  </template>
+  <emails-form
+    v-if="tabKey === configKeysEnum.EMAILS"
+    v-model="config[configKeysEnum.EMAILS]"
+  />
+  <config-form
+    :title="configKeysEnum.UPLOADERSS3"
+    v-if="tabKey === configKeysEnum.UPLOAD"
+    v-model="config[configKeysEnum.UPLOADERSS3]"
+    showTitle
+  />
+  <config-form
+    :title="configKeysEnum.UPLOADERSLOCAL"
+    v-if="tabKey === configKeysEnum.UPLOAD"
+    v-model="config[configKeysEnum.UPLOADERSLOCAL]"
+    showTitle
+  />
+  <config-form
+    :title="configKeysEnum.UPLOADERSMDII"
+    v-if="tabKey === configKeysEnum.UPLOAD"
+    v-model="config[configKeysEnum.UPLOADERSMDII]"
+    show-title
+  />
+  <config-form
+    :title="configKeysEnum.MARKUP"
+    v-if="tabKey === configKeysEnum.FRONTEND_CONFIGURATIONS"
+    v-model="config[configKeysEnum.MARKUP]"
+    showTitle
+  />
+  <config-form
+    :title="configKeysEnum.CHAT"
+    v-if="tabKey === configKeysEnum.FRONTEND_CONFIGURATIONS"
+    v-model="config[configKeysEnum.CHAT]"
+    showTitle
+  />
+  <emoji-form
+    :title="configKeysEnum.EMOJI"
+    v-if="tabKey === configKeysEnum.FRONTEND_CONFIGURATIONS"
+    v-model="config[configKeysEnum.EMOJI]"
+    showTitle
+  />
+  <config-form
+    :title="configKeysEnum.ECTO_REPOS"
+    v-if="tabKey === configKeysEnum.DATABASE"
+    v-model="config[configKeysEnum.ECTO_REPOS]"
+  />
+  <assets-form
+    :title="configKeysEnum.ASSETS"
+    v-show="tabKey === configKeysEnum.FRONTEND_CONFIGURATIONS"
+    v-model="config[configKeysEnum.ASSETS]"
+    showTitle
+    :error="error.assets"
+  />
+  <config-form
+    :title="configKeysEnum.KOCAPTCHA"
+    v-if="tabKey === configKeysEnum.CAPTCHA"
+    v-model="config[configKeysEnum.KOCAPTCHA]"
+    showTitle
+  />
+  <config-form
+    :title="configKeysEnum.WEB_AUTHENTICATOR"
+    v-if="tabKey === configKeysEnum.AUTH"
+    v-model="config[configKeysEnum.WEB_AUTHENTICATOR]"
+  />
+  <config-form
+    :title="configKeysEnum.LDAP"
+    v-if="tabKey === configKeysEnum.AUTH"
+    v-model="config[configKeysEnum.LDAP]"
+    showTitle
+  />
+  <config-form
+    :title="configKeysEnum.TWITTER_OAUTH"
+    v-if="tabKey === configKeysEnum.AUTH"
+    v-model="config[configKeysEnum.TWITTER_OAUTH]"
+    showTitle
+  />
+  <config-form
+    :title="configKeysEnum.FACEBOOK_OAUTH"
+    v-if="tabKey === configKeysEnum.AUTH"
+    v-model="config[configKeysEnum.FACEBOOK_OAUTH]"
+    showTitle
+  />
+  <config-form
+    :title="configKeysEnum.GOOGLE_OAUTH"
+    v-if="tabKey === configKeysEnum.AUTH"
+    v-model="config[configKeysEnum.GOOGLE_OAUTH]"
+    showTitle
+  />
+  <config-form
+    :title="configKeysEnum.MICROSOFT_OAUTH"
+    v-if="tabKey === configKeysEnum.AUTH"
+    v-model="config[configKeysEnum.MICROSOFT_OAUTH]"
+    showTitle
+  />
+  <config-form
+    :title="configKeysEnum.OAUTH2"
+    v-if="tabKey === configKeysEnum.AUTH"
+    v-model="config[configKeysEnum.OAUTH2]"
+    showTitle
+  />
+  <auto-linker-form
+    :title="configKeysEnum.AUTO_LINKER"
+    v-if="tabKey === configKeysEnum.AUTO_LINKER"
+    v-model="config[configKeysEnum.AUTO_LINKER]"
+  />
+  <mrf-subchain-form
+    :title="configKeysEnum.MRF_SUBCHAIN"
+    v-if="tabKey === configKeysEnum.MRF_SIMPLE"
+    v-model="config[configKeysEnum.MRF_SUBCHAIN]"
+    showTitle
+  />
+  <config-form
+    :title="configKeysEnum.MRF_REJECTNONPUBLIC"
+    v-if="tabKey === configKeysEnum.MRF_SIMPLE"
+    v-model="config[configKeysEnum.MRF_REJECTNONPUBLIC]"
+    showTitle
+  />
+  <config-form
+    :title="configKeysEnum.MRF_HELLTHREAD"
+    v-if="tabKey === configKeysEnum.MRF_SIMPLE"
+    v-model="config[configKeysEnum.MRF_HELLTHREAD]"
+    showTitle
+  />
+  <mrf-keyword-form
+    :title="configKeysEnum.MRF_KEYWORD"
+    v-if="tabKey === configKeysEnum.MRF_SIMPLE"
+    v-model="config[configKeysEnum.MRF_KEYWORD]"
+    showTitle
+  />
+  <config-form
+    :title="configKeysEnum.MRF_MENTION"
+    v-if="tabKey === configKeysEnum.MRF_SIMPLE"
+    v-model="config[configKeysEnum.MRF_MENTION]"
+    showTitle
+  />
+  <config-form
+    :title="configKeysEnum.MRF_NORMALIZE_MARKUP"
+    v-if="tabKey === configKeysEnum.MRF_SIMPLE"
+    v-model="config[configKeysEnum.MRF_NORMALIZE_MARKUP]"
+    showTitle
+  />
+  <m-r-f-user-allowlist-form
+    :title="configKeysEnum.MRF_USER_ALLOWLIST"
+    v-if="tabKey === configKeysEnum.MRF_SIMPLE"
+    v-model="config[configKeysEnum.MRF_USER_ALLOWLIST]"
+    showTitle
+  />
+  <config-form
+    :title="configKeysEnum.MRF_VOCABULARY"
+    v-if="tabKey === configKeysEnum.MRF_SIMPLE"
+    v-model="config[configKeysEnum.MRF_VOCABULARY]"
+    showTitle
+  />
+  <config-form
+    :title="configKeysEnum.WEB_FEDERATOR_RETRY_QUEUE"
+    v-if="tabKey === configKeysEnum.JOB_QUEUE"
+    v-model="config[configKeysEnum.WEB_FEDERATOR_RETRY_QUEUE]"
+    showTitle
+  />
+</div>
+</template>
+
+<script lang="ts">
+import { Component, Prop, Vue } from 'vue-property-decorator'
+import { FulfillingBouncingCircleSpinner } from 'epic-spinners'
+import { configKeys } from '../../data/Config'
+import EmailsForm from './forms/EmailsForm.vue'
+import AutoLinkerForm from './forms/AutoLinkerForm.vue'
+import EmojiForm from './forms/EmojiForm.vue'
+import AssetsForm from './forms/AssetsForm.vue'
+import MrfSubchainForm from './forms/MRFSubchainForm.vue'
+import MrfKeywordForm from './forms/MRFKeywordForm.vue'
+import MRFUserAllowlistForm from './forms/MRFUserAllowlistForm.vue'
+import ConfigForm from './forms/ConfigForm.vue'
+
+@Component({
+  components: {
+    ConfigForm,
+    MRFUserAllowlistForm,
+    EmojiForm,
+    AutoLinkerForm,
+    EmailsForm,
+    AssetsForm,
+    MrfSubchainForm,
+    MrfKeywordForm,
+    FulfillingBouncingCircleSpinner
+  },
+})
+export default class ConfigSettingsForms extends Vue {
+  configKeysEnum = configKeys
+  @Prop(Object) readonly value!: Object
+  @Prop(String) readonly tabKey!: String
+  @Prop(Array) readonly tabs!: Array<Object>
+  @Prop(Object) readonly error!: Object
+  showTab ({ key }) {
+    return this.tabKey === key &&
+      key !== this.configKeysEnum.AUTO_LINKER &&
+      key !== this.configKeysEnum.EMAILS &&
+      key !== this.configKeysEnum.ASSETS
+  }
+  showTabTitle ({ key }) {
+    return this.tabKey === this.configKeysEnum.LDAP ||
+      this.tabKey === this.configKeysEnum.MRF_SIMPLE
+  }
+  get config () {
+    return this.value
+  }
+  set config (value) {
+    this.$emit('change', value)
+  }
+}
+</script>
+
+<style lang="scss">
+</style>
diff --git a/src/components/configSettings/forms/AssetsForm.vue b/src/components/configSettings/forms/AssetsForm.vue
new file mode 100644
index 0000000000000000000000000000000000000000..9073a2e452479690b0be198616b0679be8c3ab8b
--- /dev/null
+++ b/src/components/configSettings/forms/AssetsForm.vue
@@ -0,0 +1,116 @@
+<template>
+  <div class="assets-form" :style="{margin: margin}">
+    <p class="note">{{$t('config_settings.:assets_form.title')}}</p>
+    <p class="title">{{$t('config_settings.:assets_form.mascots')}}</p>
+    <div class="va-row" v-for="(mascot, index) in formData.mascots" :key="index">
+      <va-input
+        v-model="formData.mascots[index].name"
+        :label="$t('config_settings.:assets_form.name')"
+        :error="!!error.mascots[index]"
+        class="assets-form__col"
+        :class="{ 'mb-0': !!error.mascots[index] }"
+      />
+      <va-input
+        v-model="formData.mascots[index].mime_type"
+        :label="$t('config_settings.:assets_form.mime_type')"
+        class="assets-form__col"
+        :error="!!error.mascots[index]"
+        :class="{ 'mb-0':!!error.mascots[index] }"
+      />
+      <va-input
+        v-model="formData.mascots[index].url"
+        :label="$t('config_settings.:assets_form.url')"
+        class="assets-form__col"
+        :error="!!error.mascots[index]"
+        :class="{ 'mb-0':!!error.mascots[index] }"
+      />
+      <va-icon
+        color="danger"
+        @click.native="removeMascots(index)"
+        name="ion-ios-trash-outline"
+        class="px-2 assets-form__delete"
+      />
+      <span class="assets-form__error pl-2" v-if="!!error.mascots[index]">
+        {{$t(`config_settings.:assets_form.${error.mascots[index]}`)}}
+      </span>
+    </div>
+    <va-button
+      small outline
+      @click="addMascot"
+      class="mx-0 mb-3"
+    >{{$t('config_settings.:assets_form.add_mascots')}}</va-button>
+    <va-select
+      :options="selectOptions"
+      :label="$t('config_settings.:assets_form.default_mascot')"
+      v-model="formData.default_mascot"
+    />
+  </div>
+</template>
+
+<script lang="ts">
+import { Component, Prop, Vue } from 'vue-property-decorator'
+import { keys, isEmpty } from 'lodash'
+import AssetsConfig from '../../../entities/settings/AssetsConfig'
+
+@Component({
+  components: {},
+})
+export default class AssetsForm extends Vue {
+  @Prop(Object) readonly value!: AssetsConfig
+  @Prop(String) readonly title!: string
+  @Prop(Boolean) readonly showTitle!: boolean
+  @Prop(String) readonly margin!: string
+  @Prop(Object) readonly error!: Object
+  get selectOptions () {
+    return this.formData.mascots.map(({ name }) => name)
+  }
+  get formData () {
+    return this.value
+  }
+  set formData (val) {
+    this.$emit('updateForm', val)
+  }
+  addMascot () {
+    this.formData.mascots.push({ name: '', mime_type: '', url: '' })
+  }
+  removeMascots (index) {
+    this.formData.mascots.splice(index, 1)
+  }
+}
+</script>
+
+<style scoped lang="scss">
+.assets-form {
+  border-top: 1px solid $border-color;
+  .va-row {
+    position: relative;
+  }
+  &__col {
+    width: 30%;
+    padding-right: .5rem;
+    padding-left: .5rem;
+    @include media-breakpoint-down(xs) {
+      width: calc(100% - 30px);
+      padding-right: 30px;
+      padding-left: 0;
+    }
+  }
+  &__delete {
+    font-size: 1.5rem;
+    cursor: pointer;
+    height: 1.5rem;
+    @include media-breakpoint-down(xs) {
+      position: absolute;
+      top: 0;
+      bottom: 0;
+      margin: auto;
+      right: 0;
+    }
+  }
+  &__error {
+    color: $danger !important;
+    @include va-title;
+    margin-bottom: .5rem;
+  }
+}
+</style>
diff --git a/src/components/configSettings/forms/AutoLinkerForm.vue b/src/components/configSettings/forms/AutoLinkerForm.vue
new file mode 100644
index 0000000000000000000000000000000000000000..8db50c47c5e6f74f16931d47694295feb2310c65
--- /dev/null
+++ b/src/components/configSettings/forms/AutoLinkerForm.vue
@@ -0,0 +1,53 @@
+<template>
+  <div class='autolinker-form config-form' :style="{margin: margin}">
+    <p class="title" v-if="showTitle">{{$t(`config_settings.${title}_form.title`)}}</p>
+    <va-checkbox v-model="formData.opts.scheme" :label="$t('config_settings.opts_form.scheme')"/>
+    <p class="note">{{$t('config_settings.opts_form.scheme_note')}}</p>
+    <va-checkbox v-model="formData.opts.extra" :label="$t('config_settings.opts_form.extra')"/>
+    <p class="note">{{$t('config_settings.opts_form.extra_note')}}</p>
+    <va-checkbox v-model="formData.opts.validate_tld" :label="$t('config_settings.opts_form.validate_tld')"/>
+    <p class="note">{{$t('config_settings.opts_form.validate_tld_note')}}</p>
+    <va-input-wrapper :class="{'mb-0': !formData.opts.class}">
+      <va-checkbox v-model="formData.opts.class" :label="$t('config_settings.opts_form.class')"/>
+    </va-input-wrapper>
+    <va-input v-model="formData.class_text" v-if="formData.opts.class" :label="$t('config_settings.opts_form.class')" class="mb-0"/>
+    <p class="note">{{$t('config_settings.opts_form.class_note')}}</p>
+    <va-input-wrapper :class="{'mb-0': !formData.opts.strip_prefix}">
+      <va-checkbox v-model="formData.opts.strip_prefix" :label="$t('config_settings.opts_form.strip_prefix')"/>
+    </va-input-wrapper>
+    <va-input v-model="formData.strip_prefix_text" v-if="formData.opts.strip_prefix" :label="$t('config_settings.opts_form.strip_prefix')" class="mb-0"/>
+    <p class="note">{{$t('config_settings.opts_form.strip_prefix_note')}}</p>
+
+    <va-checkbox v-model="formData.opts.new_window" :label="$t('config_settings.opts_form.new_window')"/>
+    <p class="note">{{$t('config_settings.opts_form.new_window_note')}}</p>
+    <va-checkbox v-model="formData.opts.rel" :label="$t('config_settings.opts_form.rel')"/>
+    <p class="note">{{$t('config_settings.opts_form.rel_note')}}</p>
+
+  </div>
+</template>
+
+<script lang="ts">
+import { Component, Prop, Vue } from 'vue-property-decorator'
+import UploadConfig from '../../../entities/settings/UploadConfig'
+import { keys } from 'lodash'
+
+@Component({
+  components: {},
+})
+export default class ConfigForm extends Vue {
+  @Prop(Object) readonly value!: UploadConfig
+  @Prop(String) readonly title!: string
+  @Prop(Boolean) readonly showTitle!: boolean
+  @Prop(String) readonly margin!: string
+  get formData () {
+    return this.value
+  }
+  set formData (val) {
+    this.$emit('updateForm', val)
+  }
+}
+</script>
+
+<style scoped lang="scss">
+
+</style>
diff --git a/src/components/configSettings/forms/ConfigForm.vue b/src/components/configSettings/forms/ConfigForm.vue
new file mode 100644
index 0000000000000000000000000000000000000000..717cfeeb4a584a2e7f93e0ed3539d7fbf2897395
--- /dev/null
+++ b/src/components/configSettings/forms/ConfigForm.vue
@@ -0,0 +1,107 @@
+<template>
+  <div class='config-form' :style="{margin: margin}">
+    <p class="title" v-if="showTitle">{{$t(`config_settings.${title}_form.title`)}}</p>
+    <template v-for="(field, index) in fields">
+      <config-form
+        v-if="field.component === 'parent'"
+        v-model="formData[field.model]"
+        :title="field.model"
+        showTitle
+        margin="1rem"
+        :key="field.model"
+      />
+      <div v-else :key="field.model">
+        <component
+          v-if="typeof formData[field.model] === 'number'"
+          :is="field.component"
+          v-model.number="formData[field.model]"
+          :label="$t(`config_settings.${title}_form.${field.model}`)"
+          class="mb-0"
+          type="number"
+        />
+        <component
+          v-else
+          :is="field.component"
+          v-model="formData[field.model]"
+          :label="$t(`config_settings.${title}_form.${field.model}`)"
+          class="mb-0"
+          :options="selectOptions[field.model]"
+          :multiple="field.multiple"
+          :type="field.isTextarea ? 'textarea' : 'text'"
+        />
+        <p
+          class="note"
+          :key="index"
+        >
+          {{$t(`config_settings.${title}_form.${field.model}_note`)}}
+        </p>
+      </div>
+    </template>
+  </div>
+</template>
+
+<script>
+import getFieldList, { selectOptions } from '../../../utils/GetFieldList'
+import { StaticRecourcesService } from '../../../services/StaticRecourcesService'
+import { keys } from 'lodash'
+import { configKeys } from '../../../data/Config'
+
+export default {
+  name: 'config-form',
+  props: {
+    value: {
+      required: true,
+    },
+    title: {
+      type: String,
+      default: ''
+    },
+    showTitle: {
+      type: Boolean,
+      default: false
+    },
+    margin: {
+      type: String,
+      default: '0'
+    }
+  },
+  data () {
+    return {
+      selectOptions
+    }
+  },
+  computed: {
+    formData: {
+      get () {
+        return this.value
+      },
+      set () {
+        this.$emit('updateForm', val)
+      }
+    },
+    fields () {
+      return getFieldList(this.formData)
+    }
+  },
+  async mounted () {
+    if (this.title === configKeys.FRONTEND_CONFIGURATIONS) {
+      const themeConfig = await StaticRecourcesService.getThemesList()
+      this.selectOptions.theme = keys(themeConfig)
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+  .config-form {
+    padding-top: 0.5rem;
+    border-top: 1px solid $border-color;
+    &:first-of-type {
+      padding-top: 0;
+      border-top: none;
+    }
+  }
+  .note {
+    margin-bottom: 1rem !important;
+  }
+</style>
diff --git a/src/components/configSettings/forms/EmailsForm.vue b/src/components/configSettings/forms/EmailsForm.vue
new file mode 100644
index 0000000000000000000000000000000000000000..17de4d4117c5d2501bdd78327db1258d256c698b
--- /dev/null
+++ b/src/components/configSettings/forms/EmailsForm.vue
@@ -0,0 +1,134 @@
+<template>
+  <div class="emails-form">
+    <va-input-wrapper>
+      <va-checkbox
+        v-model="formData.enabled"
+        :label="$t('config_settings.Pleroma.Emails.Mailer_form.enabled')"
+      />
+    </va-input-wrapper>
+    <va-input-wrapper>
+      <va-select
+        v-model="formData.adapter"
+        :label="$t('config_settings.Pleroma.Emails.Mailer_form.adapter')"
+        :options="selectOptions"
+      />
+    </va-input-wrapper>
+    <div>
+      <p class="title">{{$t('config_settings.Pleroma.Emails.Mailer_form.adapters_options')}}</p>
+      <div
+        class="va-row"
+        v-for="(option, index) in formData.adapterOptions"
+        :key="index"
+      >
+        <va-input
+          v-model="formData.adapterOptions[index].name"
+          :label="$t('config_settings.Pleroma.Emails.Mailer_form.option_name')"
+          class="emails-form__group-name"
+        />
+        <component
+          v-if="formData.adapterOptions[index].type.isNumber"
+          :is="formData.adapterOptions[index].type.component"
+          v-model.number="formData.adapterOptions[index].value"
+          type="number"
+          :label="$t('config_settings.Pleroma.Emails.Mailer_form.option_value')"
+          class="emails-form__group-value mb-3"
+        />
+        <component
+          v-else
+          :is="formData.adapterOptions[index].type.component"
+          v-model="formData.adapterOptions[index].value"
+          :label="$t('config_settings.Pleroma.Emails.Mailer_form.option_value')"
+          class="emails-form__group-value mb-3"
+        />
+        <va-icon
+          color="danger"
+          @click.native="removeOption(index)"
+          name="ion-ios-trash-outline"
+          class="px-2 emails-form__delete"
+        />
+      </div>
+      <va-button @click="addOption" outline small class="ma-0">
+        {{$t('config_settings.Pleroma.Emails.Mailer_form.add_adapted_option')}}
+      </va-button>
+      <va-modal
+        v-model="isModalShow"
+        @ok="onAddOptionConfirm"
+        >
+        <va-select
+          v-model="newComponentType"
+          :options="newComponentOptions"
+          :label="$t('config_settings.Pleroma.Emails.Mailer_form.choose_type_of_field')"
+        />
+      </va-modal>
+    </div>
+  </div>
+</template>
+
+<script lang="ts">
+import { Component, Prop, Vue, Watch } from 'vue-property-decorator'
+import { getFieldComponent, selectOptions } from '../../../utils/GetFieldList'
+import EmailsConfig, { AdapterOption } from '../../../entities/settings/EmailsConfig'
+
+@Component({
+  components: {},
+})
+export default class EmailsForm extends Vue {
+  @Prop(Object) readonly value!: EmailsConfig
+  selectOptions = selectOptions.adapter
+  newComponentOptions = [
+    { text: 'string', id: 'text' },
+    { text: 'number', id: 1 },
+    { text: 'boolean', id: true }
+  ]
+  newComponentType:any = { text: 'string', id: 'text' }
+  isModalShow:boolean = false
+  get formData () {
+    return this.value
+  }
+  set formData (val) {
+    this.$emit('updateForm', val)
+  }
+  @Watch('formData.adapter') setDefaultAdapterOption () {
+    this.formData.adapterOptions = [new AdapterOption({ type: getFieldComponent('text') })]
+  }
+  removeOption (index) {
+    this.formData.adapterOptions.splice(index, 1)
+  }
+  addOption () {
+    this.isModalShow = true
+  }
+  onAddOptionConfirm () {
+    this.formData.adapterOptions.push(new AdapterOption({ type: getFieldComponent(this.newComponentType.id) }))
+  }
+}
+</script>
+
+<style scoped lang="scss">
+.emails-form {
+  .va-row {
+    margin-left: 0 !important;
+    margin-right: 0 !important;
+    position: relative;
+  }
+  &__delete {
+    font-size: 1.5rem;
+    cursor: pointer;
+    @include media-breakpoint-down(sm) {
+      top: 0;
+      bottom: 0;
+      height: 1.5rem;
+      margin: auto;
+      right: 0;
+      position: absolute;
+    }
+  }
+  &__group-name, &__group-value {
+    padding-right: .5rem;
+    width: calc(50% - 15px);
+    @include media-breakpoint-down(sm) {
+      padding-right: 30px;
+      width: calc(100% - 30px);
+    }
+  }
+}
+</style>
diff --git a/src/components/configSettings/forms/EmojiForm.vue b/src/components/configSettings/forms/EmojiForm.vue
new file mode 100644
index 0000000000000000000000000000000000000000..fe2ea1386515ba2eeff1102e6993a5964dfaa1eb
--- /dev/null
+++ b/src/components/configSettings/forms/EmojiForm.vue
@@ -0,0 +1,105 @@
+<template>
+  <div class="emoji-form">
+    <p class="title">{{$t('config_settings.:emoji_form.title')}}</p>
+    <div class="mb-3">
+      <span class="title">{{$t('config_settings.:emoji_form.shortcode_globs')}}</span>
+      <p class="note mb-0">{{$t('config_settings.:emoji_form.shortcode_globs_note')}}</p>
+      <div v-for="(item, index) in formData.shortcode_globs" :key="index" class="va-row">
+        <va-input v-model="formData.shortcode_globs[index]"/>
+        <va-icon
+          color="danger"
+          @click.native="removeShortcodeGlob(index)"
+          name="ion-ios-trash-outline"
+          class="pl-2 emoji-form__delete"
+        />
+      </div>
+      <div class="va-row mb-2">
+        <va-button small @click="addShortcodeGlob" outline class="ma-0">
+          {{$t('config_settings.:emoji_form.add_shortcode_glob')}}
+        </va-button>
+      </div>
+    </div>
+    <va-input
+      class="mb-0"
+      v-model='formData.pack_extensions'
+      :label="$t('config_settings.:emoji_form.pack_extensions')"
+    />
+    <p class="note">{{$t('config_settings.:emoji_form.pack_extensions_note')}}</p>
+    <div class="mb-3">
+      <p class="title mb-0">{{$t('config_settings.:emoji_form.groups')}}</p>
+      <p class="note mb-0">{{$t('config_settings.:emoji_form.groups_note')}}</p>
+      <div v-for="(group, index) in formData.groups" class="va-row" :key="index">
+        <va-input v-model="formData.groups[index][0]" class="emoji-form__group-name"/>
+        <va-input v-model="formData.groups[index][1]"/>
+        <va-icon
+          color="danger"
+          @click.native="removeGroup(index)"
+          name="ion-ios-trash-outline"
+          class="pl-2 emoji-form__delete"
+        />
+      </div>
+      <div class="va-row mb-2">
+        <va-button small outline @click="addGroup" class="ma-0">Add group</va-button>
+      </div>
+    </div>
+    <va-input v-model="formData.default_manifest"/>
+  </div>
+</template>
+
+<script lang="ts">
+import { Component, Prop, Vue } from 'vue-property-decorator'
+import { selectOptions } from '../../../utils/GetFieldList'
+import { keys } from 'lodash'
+import EmojiConfig from '../../../entities/settings/EmojiConfig'
+
+@Component({
+  components: {},
+})
+export default class EmojiForm extends Vue {
+  @Prop(Object) readonly value!: EmojiConfig
+  @Prop(String) readonly title!: string
+  @Prop(Boolean) readonly showTitle!: boolean
+  @Prop(String) readonly margin!: string
+  selectOptions = selectOptions
+  get formData () {
+    return this.value
+  }
+  set formData (val) {
+    this.$emit('updateForm', val)
+  }
+  addShortcodeGlob () {
+    this.formData.shortcode_globs.push('')
+  }
+  removeShortcodeGlob (index) {
+    this.formData.shortcode_globs.splice(index, 1)
+  }
+  addGroup () {
+    this.formData.groups.push(['', ''])
+  }
+  removeGroup (index) {
+    this.formData.groups.splice(index, 1)
+  }
+}
+</script>
+
+<style scoped lang="scss">
+.emoji-form {
+  border-top: 1px solid $border-color;
+  &__delete {
+    font-size: 1.5rem;
+    cursor: pointer;
+  }
+  .va-row {
+    margin-left: 0 !important;
+    margin-right: 0 !important;
+  }
+  &__group-name {
+    margin-right: 0.5rem;
+  }
+  @include media-breakpoint-down(sm) {
+    &__group-name {
+      margin-right: 0;
+    }
+  }
+}
+</style>
diff --git a/src/components/configSettings/forms/LoggerForm.vue b/src/components/configSettings/forms/LoggerForm.vue
new file mode 100644
index 0000000000000000000000000000000000000000..5d02f92a21abced6ccb9079c425ae7a0ea6cd7f4
--- /dev/null
+++ b/src/components/configSettings/forms/LoggerForm.vue
@@ -0,0 +1,21 @@
+<template>
+<div class="logger-form">
+</div>
+</template>
+
+<script lang="ts">
+import { Component, Prop, Vue } from 'vue-property-decorator'
+import LoggerConfig from '../../../entities/settings/LoggerConfig'
+
+@Component({
+  components: {}
+})
+
+export default class InstanceForm extends Vue {
+  @Prop(Object) readonly value!: LoggerConfig
+}
+</script>
+
+<style scoped lang="scss">
+
+</style>
diff --git a/src/components/configSettings/forms/MRFKeywordForm.vue b/src/components/configSettings/forms/MRFKeywordForm.vue
new file mode 100644
index 0000000000000000000000000000000000000000..bce414dcf4bfbbf50c9ef06fa371f7e140aa7980
--- /dev/null
+++ b/src/components/configSettings/forms/MRFKeywordForm.vue
@@ -0,0 +1,93 @@
+<template>
+  <div class="mrf_keyword_form">
+    <p class="title">{{$t('config_settings.:mrf_keyword_form.title')}}</p>
+    <va-input
+      v-model="formData.reject"
+      :label="$t('config_settings.:mrf_keyword_form.reject')"
+      class="mb-0"
+    />
+    <p class="note">{{$t('config_settings.:mrf_keyword_form.reject_note')}}</p>
+    <va-input
+      v-model="formData.federated_timeline_removal"
+      :label="$t('config_settings.:mrf_keyword_form.federated_timeline_removal')"
+      class="mb-0"
+    />
+    <p class="note">{{$t('config_settings.:mrf_keyword_form.federated_timeline_removal_note')}}</p>
+    <div class="va-row" v-for="(replaceItem, index) in formData.replace" :key="index">
+      <va-input
+        v-model="formData.replace[index].pattern"
+        class="mrf_keyword_form__group-name"
+        :label="$t('config_settings.:mrf_keyword_form.pattern')"
+      />
+      <va-input
+        v-model="formData.replace[index].replacement"
+        class="mrf_keyword_form__group-value mb-3"
+        :label="$t('config_settings.:mrf_keyword_form.replacement')"
+        :tagMax="0"
+      />
+      <va-icon
+        color="danger"
+        @click.native="removeOption(index)"
+        name="ion-ios-trash-outline"
+        class="px-2 mrf_keyword_form__delete"
+      />
+    </div>
+    <va-button small outline @click="addOption">{{$t('config_settings.:mrf_keyword_form.add_replace_item')}}</va-button>
+  </div>
+</template>
+
+<script lang="ts">
+import { Component, Prop, Vue } from 'vue-property-decorator'
+import MRFKeyword, { ReplaceItemClass } from '../../../entities/settings/MRFKeyword'
+
+@Component({
+  components: {},
+})
+export default class MRFKeywordForm extends Vue {
+  @Prop(Object) readonly value!: MRFKeyword
+  get formData () {
+    return this.value
+  }
+  set formData (val) {
+    this.$emit('updateForm', val)
+  }
+  removeOption (index) {
+    this.formData.replace.splice(index, 1)
+  }
+  addOption () {
+    this.formData.replace.push(new ReplaceItemClass())
+  }
+}
+</script>
+
+<style scoped lang="scss">
+  .mrf_keyword_form {
+    padding-top: .5rem;
+    border-top: 1px solid $border-color;
+    .va-row {
+      margin-left: 0 !important;
+      margin-right: 0 !important;
+      position: relative;
+    }
+    &__delete {
+      font-size: 1.5rem;
+      cursor: pointer;
+      @include media-breakpoint-down(sm) {
+        top: 0;
+        bottom: 0;
+        height: 1.5rem;
+        margin: auto;
+        right: 0;
+        position: absolute;
+      }
+    }
+    &__group-name, &__group-value {
+      padding-right: .5rem;
+      width: calc(50% - 15px);
+      @include media-breakpoint-down(sm) {
+        padding-right: 30px;
+        width: calc(100% - 30px);
+      }
+    }
+  }
+</style>
diff --git a/src/components/configSettings/forms/MRFSubchainForm.vue b/src/components/configSettings/forms/MRFSubchainForm.vue
new file mode 100644
index 0000000000000000000000000000000000000000..ee025a896437c10b4e526316f565d276e1b3b7a3
--- /dev/null
+++ b/src/components/configSettings/forms/MRFSubchainForm.vue
@@ -0,0 +1,87 @@
+<template>
+  <div class="mrf_keyword_form">
+    <p class="title">{{$t('config_settings.:mrf_subchain_form.title')}}</p>
+    <p class="note">{{$t('config_settings.:mrf_subchain_form.note')}}</p>
+    <div class="va-row" v-for="(match_actor, index) in formData.match_actor" :key="index">
+      <va-input
+        v-model="formData.match_actor[index].regular_expression"
+        class="mrf-subchain-form__group-name"
+        :label="$t('config_settings.:mrf_subchain_form.regular_expression')"
+      />
+      <va-select
+        :options="selectOptions"
+        multiple
+        v-model="formData.match_actor[index].policy_modules"
+        class="mrf-subchain-form__group-value mb-3"
+        :label="$t('config_settings.:mrf_subchain_form.policy_modules')"
+        width="calc(50% -30px)"
+        :tagMax="0"
+      />
+      <va-icon
+        color="danger"
+        @click.native="removeOption(index)"
+        name="ion-ios-trash-outline"
+        class="px-2 mrf-subchain-form__delete"
+      />
+    </div>
+    <va-button small outline @click="addOption">{{$t('config_settings.:mrf_subchain_form.add_match_actor')}}</va-button>
+  </div>
+</template>
+
+<script lang="ts">
+import { Component, Prop, Vue } from 'vue-property-decorator'
+import MRFSubchainConfig, { MatchActor } from '../../../entities/settings/MRFSubchainConfig'
+import { selectOptions } from '../../../utils/GetFieldList'
+
+@Component({
+  components: {},
+})
+export default class MRFSubchainForm extends Vue {
+  @Prop(Object) readonly value!: MRFSubchainConfig
+  selectOptions = selectOptions.rewrite_policy
+  get formData () {
+    return this.value
+  }
+  set formData (val) {
+    this.$emit('updateForm', val)
+  }
+  removeOption (index) {
+    this.formData.match_actor.splice(index, 1)
+  }
+  addOption () {
+    this.formData.match_actor.push(new MatchActor())
+  }
+}
+</script>
+
+<style scoped lang="scss">
+  .mrf_keyword_form {
+    padding-top: .5rem;
+    border-top: 1px solid $border-color;
+    .va-row {
+      margin-left: 0 !important;
+      margin-right: 0 !important;
+      position: relative;
+    }
+    &__delete {
+      font-size: 1.5rem;
+      cursor: pointer;
+      @include media-breakpoint-down(sm) {
+        top: 0;
+        bottom: 0;
+        height: 1.5rem;
+        margin: auto;
+        right: 0;
+        position: absolute;
+      }
+    }
+    &__group-name, &__group-value {
+      padding-right: .5rem;
+      width: calc(50% - 15px);
+      @include media-breakpoint-down(sm) {
+        padding-right: 30px;
+        width: calc(100% - 30px);
+      }
+    }
+  }
+</style>
diff --git a/src/components/configSettings/forms/MRFUserAllowlistForm.vue b/src/components/configSettings/forms/MRFUserAllowlistForm.vue
new file mode 100644
index 0000000000000000000000000000000000000000..febc618e0adb633d2d2f6073e761bf06bc46955f
--- /dev/null
+++ b/src/components/configSettings/forms/MRFUserAllowlistForm.vue
@@ -0,0 +1,83 @@
+<template>
+  <div class="mrf_user_allowlist_form">
+    <p class="title">{{$t(`config_settings.${title}_form.title`)}}</p>
+    <p class="note">{{$t(`config_settings.${title}_form.note`)}}</p>
+    <div class="va-row" v-for="(domain, index) in formData.allow_list" :key="index">
+      <va-input
+        v-model="formData.allow_list[index].domain"
+        class="mrf_user_allowlist_form__group-name"
+        :label="$t(`config_settings.${title}_form.domain`)"
+      />
+      <va-input
+        v-model="formData.allow_list[index].list_of_users"
+        class="mrf_user_allowlist_form__group-value mb-3"
+        :label="$t(`config_settings.${title}_form.list_of_users`)"
+        :tagMax="0"
+      />
+      <va-icon
+        color="danger"
+        @click.native="removeOption(index)"
+        name="ion-ios-trash-outline"
+        class="px-2 mrf_user_allowlist_form__delete"
+      />
+    </div>
+    <va-button small outline @click="addOption">{{$t(`config_settings.${title}_form.add_domain`)}}</va-button>
+  </div>
+</template>
+
+<script lang="ts">
+import { Component, Prop, Vue } from 'vue-property-decorator'
+import MRFUserAllowlistConfig, { UserAllowListItem } from '../../../entities/settings/MRFUserAllowlistConfig'
+
+@Component({
+  components: {},
+})
+export default class MrfUserAllowlistForm extends Vue {
+  @Prop(Object) readonly value!: MRFUserAllowlistConfig
+  @Prop(String) readonly title!: string
+  get formData () {
+    return this.value
+  }
+  set formData (val) {
+    this.$emit('updateForm', val)
+  }
+  removeOption (index) {
+    this.formData.allow_list.splice(index, 1)
+  }
+  addOption () {
+    this.formData.allow_list.push(new UserAllowListItem())
+  }
+}
+</script>
+
+<style scoped lang="scss">
+.mrf_user_allowlist_form {
+  padding-top: .5rem;
+  border-top: 1px solid $border-color;
+  .va-row {
+    margin-left: 0 !important;
+    margin-right: 0 !important;
+    position: relative;
+  }
+  &__delete {
+    font-size: 1.5rem;
+    cursor: pointer;
+    @include media-breakpoint-down(sm) {
+      top: 0;
+      bottom: 0;
+      height: 1.5rem;
+      margin: auto;
+      right: 0;
+      position: absolute;
+    }
+  }
+  &__group-name, &__group-value {
+    padding-right: .5rem;
+    width: calc(50% - 15px);
+    @include media-breakpoint-down(sm) {
+      padding-right: 30px;
+      width: calc(100% - 30px);
+    }
+  }
+}
+</style>
diff --git a/src/components/layout/AppLayout.vue b/src/components/layout/AppLayout.vue
index 7d9c929c9620aad86cb656f5a31e6e3786c727e9..b920a5ca44699bea76c73d02948371d224556590 100644
--- a/src/components/layout/AppLayout.vue
+++ b/src/components/layout/AppLayout.vue
@@ -5,7 +5,7 @@
     <main
       slot="content"
       id="content"
-      class="content va-layout gutter--lg fluid"
+      class="va-layout gutter--lg fluid"
       role="main"
     >
       <va-pre-loader
diff --git a/src/components/layout/app-navbar/AppNavbar.vue b/src/components/layout/app-navbar/AppNavbar.vue
index 9d7fb146e95bb4d3992e1b14aaab43f24b1a7ade..a3adff2c83c7c50d1a557ed73e3beac9e27a631f 100644
--- a/src/components/layout/app-navbar/AppNavbar.vue
+++ b/src/components/layout/app-navbar/AppNavbar.vue
@@ -5,7 +5,7 @@
       <va-icon-vuestic/>
     </span>
     <div class="va-row flex-center justify--space-between">
-      <va-icon icon="i-nav-search" class="pointer"/>
+      <va-icon name="i-nav-search" class="pointer"/>
       <language-dropdown class="va-navbar__item"/>
       <profile-dropdown class="va-navbar__item">
         <span>{{username}}</span>
@@ -61,7 +61,9 @@ export default {
     if (t(key, 'username').safeObject) {
       await axiosInstance.get(urlBuilder('getUser', { id: key.username }))
         .then(({ data }) => { this.loadUserProfile(data) })
-        .catch(({ response: { data } }) => console.log(data.error))
+        .catch(e => {
+          this.$toasted.show(`Account loading: ${e}`)
+        })
     }
   }
 }
diff --git a/src/components/layout/app-navbar/components/dropdowns/LanguageDropdown.vue b/src/components/layout/app-navbar/components/dropdowns/LanguageDropdown.vue
index 4b10b865d0e4b591b40132b9d125d2d0b86aee51..357052b66c172046f3ffe233b459a37444a87a9f 100644
--- a/src/components/layout/app-navbar/components/dropdowns/LanguageDropdown.vue
+++ b/src/components/layout/app-navbar/components/dropdowns/LanguageDropdown.vue
@@ -1,25 +1,22 @@
 <template>
-    <va-dropdown
-      className="language-dropdown"
-      v-model="isShown"
-      position="B"
-      fixed
-    >
-      <va-icon slot="anchor" :icon="['flag-icon flag-icon-large', flagIconClass(currentLanguage())]"/>
-      <div class="py-3 px-2">
-        <div class="language-dropdown__item va-row align--center flex-nowrap"
-           v-for="(option, id) in options"
-           :key="id"
-           :class="{ active: option.code === currentLanguage() }"
-           @click="setLanguage(option.code)"
-        >
-          <va-icon :icon="['flag-icon flag-icon-small', flagIconClass(option.code)]"/>
-          <span class="dropdown-item__text">
-            {{ $t(`language.${option.name}`) }}
-          </span>
-        </div>
+  <va-dropdown
+    class="language-dropdown"
+  >
+    <va-icon slot="anchor" :name="['flag-icon flag-icon-large', flagIconClass(currentLanguage())]"/>
+    <div class="language-dropdown__content py-3 px-2">
+      <div class="language-dropdown__item va-row align--center"
+         v-for="(option, id) in options"
+         :key="id"
+         :class="{ active: option.code === currentLanguage() }"
+         @click="setLanguage(option.code)"
+      >
+        <va-icon :name="['flag-icon flag-icon-small', flagIconClass(option.code)]"/>
+        <span class="dropdown-item__text">
+        {{ $t(`language.${option.name}`) }}
+      </span>
       </div>
-    </va-dropdown>
+    </div>
+  </va-dropdown>
 </template>
 
 <script>
@@ -27,11 +24,6 @@ import Vue from 'vue'
 
 export default {
   name: 'language-dropdown',
-  data () {
-    return {
-      isShown: false,
-    }
-  },
   props: {
     options: {
       type: Array,
@@ -73,25 +65,25 @@ export default {
 
 <style lang="scss">
 @import '../../../../../vuestic-theme/vuestic-sass/resources/resources';
-@import "~flag-icon-css/css/flag-icon.css";
+@import "../../../../../../node_modules/flag-icon-css/css/flag-icon.css";
 
-.flag-icon-large {
-  display: block;
-  width: 31px;
-  height: 23px;
-  cursor: pointer;
-}
 .language-dropdown {
   cursor: pointer;
-  max-width: 9rem !important;
-  .flag-icon-small {
-    min-width: 1.5rem;
-    min-height: 1.5rem;
-    margin-right: .5rem;
+  &__content {
+    background-color: $dropdown-background;
+    box-shadow: $gray-box-shadow;
+    border-radius: .5rem;
+    max-width: 9rem !important;
+    .flag-icon-small {
+      min-width: 1.5rem;
+      min-height: 1.5rem;
+      margin-right: .5rem;
+    }
   }
   &__item {
     padding-bottom: 0.625rem;
     cursor: pointer;
+    flex-wrap: nowrap;
     &:last-of-type {
       padding-bottom: 0 !important;
     }
@@ -99,5 +91,11 @@ export default {
       color: $vue-green;
     }
   }
+  .flag-icon-large {
+    display: block;
+    width: 31px;
+    height: 23px;
+  }
+
 }
 </style>
diff --git a/src/components/layout/app-navbar/components/dropdowns/MessageDropdown.vue b/src/components/layout/app-navbar/components/dropdowns/MessageDropdown.vue
index 4c54d9fdf994774dc27c49d3940fc6846bf8b978..1a6abfdd34722a649d0d7abb3d21937fc5e6b2f5 100644
--- a/src/components/layout/app-navbar/components/dropdowns/MessageDropdown.vue
+++ b/src/components/layout/app-navbar/components/dropdowns/MessageDropdown.vue
@@ -1,23 +1,28 @@
 <template>
-  <va-dropdown v-model="isOpen" position="B" class="message-dropdown py-3 px-2">
+  <va-dropdown
+    class="message-dropdown"
+  >
     <va-icon
-      icon="i-nav-messages"
-      :class="{'unread': !allRead}"
-      slot="actuator"
+      name="i-nav-messages"
+      slot="anchor"
+      class="message-dropdown__icon"
+      :class="{'message-dropdown__icon--unread': !allRead}"
     />
-    <div
-      v-for="option in computedOptions"
-      :key="option.id"
-      class="message-dropdown__item position-relative pr-3 flex-nowrap va-row"
-      :class="{'unread': option.unread}"
-      @click="markAsRead(option.id)"
-    >
-      <img :src="option.details.avatar" class="message-dropdown__item__avatar mr-1"/>
-      <span class="ellipsis">{{ $t(`messages.${option.name}`, { name: option.details.name})}}</span>
-    </div>
-    <div class="va-row justify--space-between">
-      <va-button>{{ $t('messages.all') }}</va-button>
-      <va-button outline @click="markAllAsRead" :disabled="allRead">{{ $t('messages.mark_as_read') }}</va-button>
+    <div class="message-dropdown__content py-3 px-2">
+      <div
+        v-for="option in computedOptions"
+        :key="option.id"
+        class="message-dropdown__item pr-3 va-row"
+        :class="{'message-dropdown__item--unread': option.unread}"
+        @click="option.unread = false"
+      >
+        <img :src="option.details.avatar" class="message-dropdown__item__avatar mr-1"/>
+        <span class="ellipsis">{{ $t(`messages.${option.name}`, { name: option.details.name})}}</span>
+      </div>
+      <div class="va-row justify--space-between">
+        <va-button class="m-0 mr-1" small>{{ $t('messages.all') }}</va-button>
+        <va-button class="m-0" small outline @click="markAllAsRead" :disabled="allRead">{{ $t('messages.mark_as_read') }}</va-button>
+      </div>
     </div>
   </va-dropdown>
 </template>
@@ -27,8 +32,7 @@ export default {
   name: 'message-dropdown',
   data () {
     return {
-      isOpen: false,
-      computedOptions: this.options.map(item => ({ ...item, unread: true })),
+      computedOptions: [...this.options],
     }
   },
   props: {
@@ -38,11 +42,13 @@ export default {
         {
           name: 'new',
           details: { name: 'Oleg M', avatar: 'https://picsum.photos/24?image=1083' },
+          unread: true,
           id: 1,
         },
         {
           name: 'new',
           details: { name: 'Andrei H', avatar: 'https://picsum.photos/24?image=1025' },
+          unread: true,
           id: 2,
         },
       ],
@@ -54,11 +60,6 @@ export default {
     },
   },
   methods: {
-    markAsRead (id) {
-      this.computedOptions = this.computedOptions.map(item => item.id === id
-        ? { ...item, unread: false }
-        : { ...item })
-    },
     markAllAsRead () {
       this.computedOptions = this.computedOptions.map(item => ({ ...item, unread: false }))
     },
@@ -68,30 +69,40 @@ export default {
 
 <style lang="scss">
 @import '../../../../../vuestic-theme/vuestic-sass/resources/resources';
-.i-nav-messages {
-  position: relative;
+
+.message-dropdown {
   cursor: pointer;
-  &.unread::before {
-    content: '';
-    position: absolute;
-    right: 0;
-    left: 0;
-    top: -.5rem;
-    background-color: $brand-danger;
-    height: .375rem;
-    width: .375rem;
-    margin: 0 auto;
-    border-radius: .187rem;
+
+  .message-dropdown__icon {
+    position: relative;
+    display: flex;
+    align-items: center;
+
+    &--unread::before {
+      content: '';
+      position: absolute;
+      right: 0;
+      left: 0;
+      top: -.5rem;
+      background-color: $brand-danger;
+      height: .375rem;
+      width: .375rem;
+      margin: 0 auto;
+      border-radius: .187rem;
+    }
+  }
+  &__content {
+    background-color: $dropdown-background;
+    box-shadow: $gray-box-shadow;
+    border-radius: .5rem;
   }
-}
-.message-dropdown {
-  max-width: 25rem;
-  margin-left: -2rem;
   &__item {
     cursor: pointer;
     margin-bottom: .75rem;
     color: $brand-secondary;
-    &.unread {
+    position: relative;
+    flex-wrap: nowrap;
+    &--unread {
       color: $vue-darkest-blue;
       &:after {
         content: '';
@@ -111,7 +122,7 @@ export default {
     }
     &__avatar {
       border-radius: 50%;
-      width: 1.5rem;
+      min-width: 1.5rem;
       height: 1.5rem;
     }
   }
diff --git a/src/components/layout/app-navbar/components/dropdowns/NotificationDropdown.vue b/src/components/layout/app-navbar/components/dropdowns/NotificationDropdown.vue
index cce413cbacfafceecd5caaac7a4249da1de1fd72..aab2071ed34ef8471413541ae48dc6d074bf0172 100644
--- a/src/components/layout/app-navbar/components/dropdowns/NotificationDropdown.vue
+++ b/src/components/layout/app-navbar/components/dropdowns/NotificationDropdown.vue
@@ -1,31 +1,32 @@
 <template>
-  <va-dropdown
-    v-model="isShown"
-    position="B"
-    class="notification-dropdown py-3 px-2"
-  >
-    <va-icon
-      icon="i-nav-notification"
-      :class="{'unread': !allRead}"
-      slot="actuator"
-    />
-    <div
-      v-for="option in computedOptions"
-      :key="option.id"
-      class="notification-dropdown__item position-relative pr-3 flex-nowrap va-row"
-      :class="{'unread': option.unread}"
-      @click="markAsRead(option.id)"
-     >
-      <img v-if="option.details.avatar" class="mr-1 notification-dropdown__item__avatar" :src="option.details.avatar"/>
-      <span class="ellipsis">{{$t(`notifications.${option.name}`,
-        { name: option.details.name, type: option.details.type })}}
-      </span>
-    </div>
-    <div class="va-row justify--space-between">
-      <va-button>{{ $t('notifications.all') }}</va-button>
-      <va-button outline @click="markAllAsRead" :disabled="allRead">{{ $t('notifications.mark_as_read') }}</va-button>
-    </div>
-  </va-dropdown>
+    <va-dropdown
+      class="notification-dropdown"
+    >
+      <va-icon
+        slot="anchor"
+        name="i-nav-notification"
+        class="notification-dropdown__icon"
+        :class="{'notification-dropdown__icon--unread': !allRead}"
+      />
+      <div class="notification-dropdown__content py-3 px-2">
+        <div
+          v-for="option in computedOptions"
+          :key="option.id"
+          class="notification-dropdown__item pr-3 va-row"
+          :class="{'notification-dropdown__item--unread': option.unread}"
+          @click="option.unread = false"
+         >
+          <img v-if="option.details.avatar" class="mr-1 notification-dropdown__item__avatar" :src="option.details.avatar"/>
+          <span class="ellipsis">
+            {{$t(`notifications.${option.name}`, { name: option.details.name, type: option.details.type })}}
+          </span>
+        </div>
+        <div class="va-row justify--space-between">
+          <va-button class="m-0 mr-1" small>{{ $t('notifications.all') }}</va-button>
+          <va-button class="m-0" small outline @click="markAllAsRead" :disabled="allRead">{{ $t('notifications.mark_as_read') }}</va-button>
+        </div>
+      </div>
+    </va-dropdown>
 </template>
 
 <script>
@@ -33,8 +34,7 @@ export default {
   name: 'notification-dropdown',
   data () {
     return {
-      isShown: false,
-      computedOptions: this.options.map(item => ({ ...item, unread: true })),
+      computedOptions: [...this.options],
     }
   },
   props: {
@@ -44,16 +44,19 @@ export default {
         {
           name: 'sentMessage',
           details: { name: 'Vasily S', avatar: 'https://picsum.photos/100' },
+          unread: true,
           id: 1,
         },
         {
           name: 'uploadedZip',
           details: { name: 'Oleg M', avatar: 'https://picsum.photos/100', type: 'typography component' },
+          unread: true,
           id: 2,
         },
         {
           name: 'startedTopic',
           details: { name: 'Andrei H', avatar: 'https://picsum.photos/24' },
+          unread: true,
           id: 3,
         },
       ],
@@ -65,11 +68,6 @@ export default {
     },
   },
   methods: {
-    markAsRead (id) {
-      this.computedOptions = this.computedOptions.map(item => item.id === id
-        ? { ...item, unread: false }
-        : { ...item })
-    },
     markAllAsRead () {
       this.computedOptions = this.computedOptions.map(item => ({ ...item, unread: false }))
     },
@@ -80,32 +78,39 @@ export default {
 <style lang="scss">
 @import '../../../../../vuestic-theme/vuestic-sass/resources/resources';
 
-.i-nav-notification {
-  position: relative;
+.notification-dropdown {
   cursor: pointer;
+  .notification-dropdown__icon {
+    position: relative;
+    display: flex;
+    align-items: center;
 
-  &.unread::before {
-    content: '';
-    position: absolute;
-    right: 0;
-    left: 0;
-    top: -.5rem;
-    background-color: $brand-danger;
-    height: .375rem;
-    width: .375rem;
-    margin: 0 auto;
-    border-radius: .187rem;
+    &--unread::before {
+      content: '';
+      position: absolute;
+      right: 0;
+      left: 0;
+      top: -.5rem;
+      background-color: $brand-danger;
+      height: .375rem;
+      width: .375rem;
+      margin: 0 auto;
+      border-radius: .187rem;
+    }
+  }
+  &__content {
+    background-color: $dropdown-background;
+    box-shadow: $gray-box-shadow;
+    border-radius: .5rem;
+    max-width: 25rem;
   }
-}
-
-.notification-dropdown {
-  max-width: 25rem;
-  margin-left: -2rem;
   &__item {
     cursor: pointer;
     margin-bottom: .75rem;
     color: $brand-secondary;
-    &.unread {
+    flex-wrap: nowrap;
+    position: relative;
+    &--unread {
       color: $vue-darkest-blue;
       &:after {
         content: '';
diff --git a/src/components/layout/app-navbar/components/dropdowns/ProfileDropdown.vue b/src/components/layout/app-navbar/components/dropdowns/ProfileDropdown.vue
index 6268fe1a16a9c0af924d39f965a3c88805b5e2c0..034bc832a569df53e72fdbcc94aba2e44ad6e70d 100644
--- a/src/components/layout/app-navbar/components/dropdowns/ProfileDropdown.vue
+++ b/src/components/layout/app-navbar/components/dropdowns/ProfileDropdown.vue
@@ -1,14 +1,14 @@
 <template>
   <va-dropdown
-    v-model="isShown"
-    position="B"
-    className="profile-dropdown pa-3"
+    class="profile-dropdown"
+    @show="toggleVisibility(true)"
+    @hide="toggleVisibility(false)"
   >
     <span class="profile-dropdown__actuator" slot="anchor">
       <slot/>
-      <va-icon class="pa-1" :icon="`fa ${isShown ? 'fa-chevron-up' :'fa-chevron-down'}`"></va-icon>
+      <va-icon class="pa-1" :name="`fa ${isShown ? 'fa-chevron-up' :'fa-chevron-down'}`"/>
     </span>
-    <div class="pa-3">
+    <div class="profile-dropdown__content py-3 px-2">
       <router-link
         v-for="option in options"
         :key="option.name"
@@ -44,6 +44,11 @@ export default {
       ],
     },
   },
+  methods: {
+    toggleVisibility (val) {
+      this.isShown = val
+    },
+  },
 }
 </script>
 
@@ -52,12 +57,19 @@ export default {
   cursor: pointer;
   &__actuator {
     color: $vue-green;
-    cursor: pointer;
-    font-size: 1.3rem;
+  }
+  .va-dropdown-popper__anchor {
+    display: flex;
+    justify-content: flex-end;
+  }
+  &__content {
+    background-color: $dropdown-background;
+    box-shadow: $gray-box-shadow;
+    border-radius: .5rem;
   }
   &__item {
     display: block;
-    color: $text-gray;
+    color: $vue-darkest-blue;
 
     &:hover, &:active {
       color: $vue-green;
diff --git a/src/components/layout/app-navbar/components/dropdowns/SettingsDropdown.vue b/src/components/layout/app-navbar/components/dropdowns/SettingsDropdown.vue
new file mode 100644
index 0000000000000000000000000000000000000000..bf5f24cc55646973872cc62dc862b2dcf5d6f352
--- /dev/null
+++ b/src/components/layout/app-navbar/components/dropdowns/SettingsDropdown.vue
@@ -0,0 +1,75 @@
+<template>
+  <va-dropdown class="settings-dropdown">
+    <va-icon
+      name="vuestic-iconset vuestic-iconset-settings"
+      color="white"
+      style="font-size: 1.4rem; display: flex;"
+      class="settings-dropdown__icon"
+      slot="anchor"
+    />
+    <div class="settings-dropdown__content py-4 px-4">
+      <div class="title settings-dropdown__content-label">{{$t('dashboard.navigationLayout')}}</div>
+      <va-button-toggle
+        outline
+        v-model="navbarViewProxy"
+        :options="options"
+        class="settings-dropdown__control"
+      />
+    </div>
+  </va-dropdown>
+</template>
+
+<script>
+export default {
+  name: 'settings-dropdown',
+  components: {},
+  props: {
+    navbarView: Boolean,
+  },
+  data () {
+    return {
+      options: [
+        { label: this.$t('dashboard.topBarButton'), value: 'true' },
+        { label: this.$t('dashboard.sideBarButton'), value: 'false' },
+      ],
+    }
+  },
+  computed: {
+    navbarViewProxy: {
+      set (navbarView) {
+        this.$emit('update:navbarView', navbarView === 'true')
+      },
+      get () {
+        return this.navbarView + ''
+      },
+    },
+  },
+}
+</script>
+
+<style lang="scss">
+@import '../../../../../vuestic-theme/vuestic-sass/resources/resources';
+
+.settings-dropdown {
+  cursor: pointer;
+
+  &__icon {
+    position: relative;
+    display: flex;
+    align-items: center;
+  }
+  &__content {
+    background-color: $dropdown-background;
+    box-shadow: $gray-box-shadow;
+    border-radius: .5rem;
+    &-label {
+      margin-bottom: .5rem;
+    }
+  }
+  &__control {
+    .va-button-group {
+      margin: 0;
+    }
+  }
+}
+</style>
diff --git a/src/components/layout/app-sidebar/AppSidebar.vue b/src/components/layout/app-sidebar/AppSidebar.vue
index c65fc29474ed67c75247c12a1bee462877a243ce..2e8ec8db62f3c0921329cfdcad85fc73c45facf8 100644
--- a/src/components/layout/app-sidebar/AppSidebar.vue
+++ b/src/components/layout/app-sidebar/AppSidebar.vue
@@ -3,7 +3,7 @@
     <template slot="menu">
       <li class="sidebar-link" @click="$router.push('/')" >
       <a class="sidebar-link__router-link" :class="{'sidebar-link__router-link--active': $route.path==='/'}">
-        <va-icon icon="sidebar-link__content__icon vuestic-iconset vuestic-iconset-user"/>
+        <va-icon name="sidebar-link__content__icon vuestic-iconset vuestic-iconset-user"/>
         <div class="sidebar-link__content__title">{{ $t('menu.users') }}
         </div>
       </a>
@@ -14,6 +14,12 @@
       >
         <template slot="title">{{ $t('menu.reports') }}</template>
       </sidebar-link>
+      <sidebar-link
+        :to="{ name: 'config' }"
+        icon="vuestic-iconset vuestic-iconset-settings"
+      >
+        <template slot="title">{{ $t('menu.config') }}</template>
+      </sidebar-link>
     </template>
   </va-sidebar>
 </template>
diff --git a/src/components/layout/app-sidebar/components/SidebarLink.vue b/src/components/layout/app-sidebar/components/SidebarLink.vue
index a9b0fdec8158576c13443f01cba56715e376cea3..c5e5659a92890c7bda83fdf090f933727d528d8c 100644
--- a/src/components/layout/app-sidebar/components/SidebarLink.vue
+++ b/src/components/layout/app-sidebar/components/SidebarLink.vue
@@ -13,7 +13,7 @@
         v-if="icon"
         class="sidebar-link__content__icon"
         :style="iconStyles"
-        :icon="icon"
+        :name="icon"
       />
       <div class="sidebar-link__content__title">
         <slot name="title"/>
diff --git a/src/components/pages/configSettings/ConfigSettingsPage.vue b/src/components/pages/configSettings/ConfigSettingsPage.vue
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..edd50435463b7a2e9f2aff84d12696023b3a1997 100644
--- a/src/components/pages/configSettings/ConfigSettingsPage.vue
+++ b/src/components/pages/configSettings/ConfigSettingsPage.vue
@@ -0,0 +1,145 @@
+<template>
+  <va-card class="config-settings-page" title="Settings">
+    <va-tabs v-model="value">
+      <va-tab
+        v-for="item in tabs"
+        :key="item.key"
+      >
+        {{$t(`config_settings.tabs.${item.key}`)}}
+      </va-tab>
+    </va-tabs>
+    <div class="config-settings-page__content pt-4">
+      <config-settings-forms
+        v-if="config"
+        v-model="config"
+        :tabKey="currentTabKey"
+        :tabs="tabs"
+        :error="error"
+      />
+      <div class="loading flex-center" v-if="loading">
+        <fulfilling-bouncing-circle-spinner
+          :animation-duration="2500"
+          :size="70"
+          color="#4ae387"
+        />
+      </div>
+    </div>
+    <div class="flex-center pb-4">
+      <va-button @click="onSaveButtonClick">Save settings</va-button>
+    </div>
+  </va-card>
+</template>
+
+<script lang="ts">
+import { Component, Vue } from 'vue-property-decorator'
+import { FulfillingBouncingCircleSpinner } from 'epic-spinners'
+import { ConfigService } from '../../../services/ConfigService'
+import { configKeysTabs, configKeys } from '../../../data/Config'
+import EmailsForm from '../../configSettings/forms/EmailsForm.vue'
+import ConvertConfigToState from '../../../utils/ConvertConfigToState'
+import ConvertConfigToApiRequest from '../../../utils/ConvertConfigToApiRequest'
+import AutoLinkerForm from '../../configSettings/forms/AutoLinkerForm.vue'
+import EmojiForm from '../../configSettings/forms/EmojiForm.vue'
+import AssetsForm from '../../configSettings/forms/AssetsForm.vue'
+import MrfSubchainForm from '../../configSettings/forms/MRFSubchainForm.vue'
+import MrfKeywordForm from '../../configSettings/forms/MRFKeywordForm.vue'
+import MRFUserAllowlistForm from '../../configSettings/forms/MRFUserAllowlistForm.vue'
+import ConfigForm from '../../configSettings/forms/ConfigForm.vue'
+import ConfigSettingsForms from '../../configSettings/ConfigSettingsForms.vue'
+
+@Component({
+  components: {
+    ConfigSettingsForms,
+    ConfigForm,
+    MRFUserAllowlistForm,
+    EmojiForm,
+    AutoLinkerForm,
+    EmailsForm,
+    AssetsForm,
+    MrfSubchainForm,
+    MrfKeywordForm,
+    FulfillingBouncingCircleSpinner
+  },
+})
+export default class ConfigSettingsPage extends Vue {
+  value:number = 0
+  config:any = null
+  configKeysEnum = configKeys
+  loading:boolean = false
+  error: {assets: {mascots?: any}} = { assets: { mascots: [] } }
+  async mounted () {
+    this.loading = true
+    try {
+      const { configs } = await ConfigService.listConfigSettings()
+      if (!configs.length) {
+        await ConfigService.setConfigToDB()
+        const { configs } = await ConfigService.listConfigSettings()
+        this.loadConfigs(configs)
+      } else {
+        this.loadConfigs(configs)
+      }
+    } catch (e) {
+      (this as any).$toasted.show(e)
+    } finally {
+      this.loading = false
+    }
+  }
+  async onSaveButtonClick () {
+    this.loading = true
+    if (this.validateForms()) {
+      try {
+        const { configs } = await ConfigService.updateConfigSettings(ConvertConfigToApiRequest(this.config))
+        this.loadConfigs(configs)
+      } catch (e) {
+        (this as any).$toasted.show(e)
+      } finally {
+        this.loading = false
+      }
+    } else {
+      (this as any).$toasted.show('Something went wrong')
+      this.loading = false
+    }
+  }
+  loadConfigs (configs) {
+    const config = ConvertConfigToState(configs)
+    this.config = config
+  }
+  showTab ({ key }) {
+    return this.currentTabKey === key &&
+      key !== this.configKeysEnum.AUTO_LINKER &&
+      key !== this.configKeysEnum.EMAILS &&
+      key !== this.configKeysEnum.ASSETS
+  }
+  showTabTitle ({ key }) {
+    return this.currentTabKey === this.configKeysEnum.LDAP ||
+      this.currentTabKey === this.configKeysEnum.MRF_SIMPLE
+  }
+  get currentTabKey () {
+    return this.tabs[this.value].key
+  }
+  get tabs () {
+    return configKeysTabs.filter(({ tab }) => tab)
+  }
+  validateForms () {
+    this.error.assets.mascots = this.config[configKeys.ASSETS].mascots.map((item) => (!item.name.length || !item.url.length || !item.mime_type.length ? 'mascots_error' : ''))
+    return this.error.assets.mascots.findIndex(error => error.length) === -1
+  }
+}
+</script>
+
+<style lang="scss">
+  .config-settings-page {
+    .note {
+      font-size: .625rem;
+      opacity: .7;
+      margin-bottom: 1rem;
+    }
+    .va-select {
+      margin-bottom: 0;
+    }
+    .captcha-form {
+      padding-bottom: 1rem;
+      border-bottom: 1px solid $border-color;
+    }
+  }
+</style>
diff --git a/src/components/pages/users/UsersPage.vue b/src/components/pages/users/UsersPage.vue
index a1066013bb98afeaf875a6bf9edc231813a2b5ea..956c057534610f7680d505ba18d74155df2cc21d 100644
--- a/src/components/pages/users/UsersPage.vue
+++ b/src/components/pages/users/UsersPage.vue
@@ -55,6 +55,7 @@ import UsersAdminPanel from '../../admin/UsersAdminPanel.vue'
 import { UsersService } from '../../../services/UsersService'
 import { RawLocation } from 'vue-router'
 import approx from 'approximate-number'
+import t from 'typy'
 
 @Component({
   components: { UsersAdminPanel, UsersTable, FulfillingBouncingCircleSpinner },
@@ -137,7 +138,9 @@ export default class Users extends Vue {
         this.loading = false
       }
     } catch (e) {
-      (this as any).$toasted.show(e.data.errors.detail)
+      (this as any).$toasted.show(t(e, 'data.errors.detail').safeObject || 'Error: Network error')
+    } finally {
+      this.loading = false
     }
   }
   selectAll (val) {
diff --git a/src/components/reports/Report.vue b/src/components/reports/Report.vue
index 30a1bd3d4c89aa78ec8365792a2c68b1a03c054d..f9c4d3074f4b4b0ec3542fe5a982d9152c8364e9 100644
--- a/src/components/reports/Report.vue
+++ b/src/components/reports/Report.vue
@@ -103,7 +103,7 @@
 <script lang="ts">
 import { Component, Vue, Prop } from 'vue-property-decorator'
 import { Report as ReportClass } from '../../entities'
-import utils from '../../services/utils.js'
+import utils from '../../utils/utils.js'
 import Status from '../statuses/Status.vue'
 
 @Component({
diff --git a/src/components/reports/ReportGroup.vue b/src/components/reports/ReportGroup.vue
index bf6701b3d9659d88d0e2e0970f1e8fa42ca93ec7..432b2362ec091a28c0774ba6d007d7509e756373 100644
--- a/src/components/reports/ReportGroup.vue
+++ b/src/components/reports/ReportGroup.vue
@@ -33,7 +33,7 @@
 import { Component, Vue, Prop } from 'vue-property-decorator'
 import { Report } from '../../entities/'
 import { getGradientBackground } from '../../services/color-functions'
-import utils from '../../services/utils'
+import utils from '../../utils/utils'
 
 @Component({
   components: {},
diff --git a/src/data/Config.ts b/src/data/Config.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b398c359f1fd396727e32d8c17e583821eff2109
--- /dev/null
+++ b/src/data/Config.ts
@@ -0,0 +1,479 @@
+import UploadConfig from '../entities/settings/UploadConfig'
+import UploadersS3Config from '../entities/settings/UploadersS3Config'
+import UriSchemesConfig from '../entities/settings/UriSchemesConfig'
+import UploadersLocalConfig from '../entities/settings/UploadersLocalConfig'
+import InstanceConfig from '../entities/settings/InstanceConfig'
+import LoggerConfig from '../entities/settings/LoggerConfig'
+import FrontentConfigurationsConfig from '../entities/settings/FrontentConfigurationsConfig'
+import CaptchaConfig from '../entities/settings/CaptchaConfig'
+import KocaptchaConfig from '../entities/settings/KocaptchaConfig'
+import DatabaseConfig from '../entities/settings/DatabaseConfig'
+import MediaProxyConfig from '../entities/settings/MediaProxyConfig'
+import LdapConfig from '../entities/settings/LdapConfig'
+import ActivityPubConfig from '../entities/settings/ActivityPubConfig'
+import UserConfig from '../entities/settings/UserConfig'
+import HttpSecurityConfig from '../entities/settings/HttpSecurityConfig'
+import RichMediaConfig from '../entities/settings/RichMediaConfig'
+import FetchInitialPostsConfig from '../entities/settings/FetchInitialPostsConfig'
+import HackneyPoolsConfig from '../entities/settings/HackneyPoolsConfig'
+import AutoLinkerConfig, {normalizeAutoLinkerConfig} from '../entities/settings/AutoLinkerConfig'
+import ScheduledActivityConfig from '../entities/settings/ScheduledActivityConfig'
+import Oauth2Config from '../entities/settings/Oauth2Config'
+import RateLimitConfig, {normalizeRateLimitConfig} from '../entities/settings/RateLimitConfig'
+import ChatConfig from '../entities/settings/ChatConfig'
+import GopherConfig, {normalizeGopherConfig} from '../entities/settings/GopherConfig'
+import EmojiConfig, {normalizeEmojiConfig} from '../entities/settings/EmojiConfig'
+import EmailsConfig, {normalizeEmailsConfig} from '../entities/settings/EmailsConfig'
+import AssetsConfig, {normalizeAssetsConfig} from '../entities/settings/AssetsConfig'
+import MRFSimple from '../entities/settings/MRFSimple'
+import MRFSubchainConfig, {normalizeMRFSubchainConfig} from '../entities/settings/MRFSubchainConfig'
+import MRFRejectnonpublic from '../entities/settings/MRFRejectnonpublic'
+import MRFHellthread from '../entities/settings/MRFHellthread'
+import MRFKeyword, {normalizeMrfKeywordConfig} from '../entities/settings/MRFKeyword'
+import MRFMention from '../entities/settings/MRFMention'
+import SuggestionsConfig from '../entities/settings/SuggestionsConfig'
+import EctoReposConfig, {normalizeEctoReposConfig} from '../entities/settings/EctoReposConfig'
+import VapidDetailsConfig from '../entities/settings/VapidDetailsConfig'
+import MRFUserAllowlist, {normalizeMRFUserAllowlistConfig} from '../entities/settings/MRFUserAllowlistConfig'
+import MRFNormalizeMarkupConfig from '../entities/settings/MRFNormalizeMarkupConfig'
+import WebEndpointConfig, {normalizeWebEndpointConfig} from '../entities/settings/WebEndpointConfig'
+import WebMetadataConfig from '../entities/settings/WebMetadataConfig'
+import UploadersMDIIConfig from '../entities/settings/UploadersMDIIConfig'
+import JobQueueConfig from '../entities/settings/JobQueueConfig'
+import WebFederationQueueConfig from '../entities/settings/WebFederationQueueConfig'
+import AuthConfig from '../entities/settings/AuthConfig'
+import AdminTokenConfig, {normalizeAdminTokenConfig} from '../entities/settings/AdminTokenConfig'
+import {
+  UeberauthFacebookOAuth,
+  UeberauthGoogleOAuth, UeberauthMicrosoftOAuth,
+  UeberauthTwitterOAuth
+} from '../entities/settings/UeberauthConfigs'
+import WebAuthenticatorConfig, {normalizeWebAuthenticatorConfig} from '../entities/settings/WebAuthenticatorConfig'
+import MarkupConfig from '../entities/settings/MarkupConfig'
+import EsshdConfig from "../entities/settings/EsshdConfig";
+import MrfVocabularyConfig from "../entities/settings/MrfVocabularyConfig";
+
+export enum configGroups {
+  PLEROMA = 'pleroma',
+  PLEROMA_JOB_QUEUE = 'pleroma_job_queue',
+  LOGGER = ':logger',
+  UEBERAUTH = 'ueberauth',
+  ESSHD = ':esshd',
+  PUSH_ENCRYPTION = ':web_push_encryption'
+}
+
+export enum configKeys {
+  UPLOAD = 'Pleroma.Upload',
+  UPLOADERSS3 = 'Pleroma.Uploaders.S3',
+  UPLOADERSLOCAL = 'Pleroma.Uploaders.Local',
+  UPLOADERSMDII = 'Pleroma.Uploaders.MDII',
+  EMAILS = 'Pleroma.Emails.Mailer',
+  URI_SCHEMES = ':uri_schemes',
+  INSTANCE = ':instance',
+  LOGGER = ':logger',
+  FRONTEND_CONFIGURATIONS = ':frontend_configurations',
+  CHAT = ':chat',
+  EMOJI = ':emoji',
+  ASSETS = ':assets',
+  WEB_ENDPOINT = 'Pleroma.Web.Endpoint',
+  WEB_METADATA = 'Pleroma.Web.Metadata',
+  CAPTCHA = 'Pleroma.Captcha',
+  KOCAPTCHA = 'Pleroma.Captcha.Kocaptcha',
+  RICH_MEDIA = ':rich_media',
+  FETCH_INITIAL_POSTS = ':fetch_initial_posts',
+  HACKNEY_POOLS = ':hackney_pools',
+  ECTO_REPOS = ':ecto_repos',
+  DATABASE = ':database',
+  MEDIA_PROXY = ':media_proxy',
+  GOPHER = ':gopher',
+  LDAP = ':ldap',
+  ACTIVITY_PUB = ':activitypub',
+  USER = ':user',
+  HTTP_SECURITY = ':http_security',
+  AUTO_LINKER = ':auto_linker',
+  SCHEDULED_ACTIVITY = 'Pleroma.ScheduledActivity',
+  WEB_AUTHENTICATOR = 'Pleroma.Web.Auth.Authenticator',
+  AUTH = ':auth',
+  OAUTH2 = ':oauth2',
+  RATE_LIMIT = ':rate_limit',
+  MRF_SIMPLE = ':mrf_simple',
+  MRF_SUBCHAIN = ':mrf_subchain',
+  MRF_REJECTNONPUBLIC = ':mrf_rejectnonpublic',
+  MRF_HELLTHREAD = ':mrf_hellthread',
+  MRF_KEYWORD = ':mrf_keyword',
+  MRF_MENTION = ':mrf_mention',
+  MRF_USER_ALLOWLIST = ':mrf_user_allowlist',
+  MRF_NORMALIZE_MARKUP = ':mrf_normalize_markup',
+  MRF_VOCABULARY = ':mrf_vocabulary',
+  SUGGESTIONS = ':suggestions',
+  VAPID_DETAILS = ':vapid_details',
+  JOB_QUEUE = ':queues',
+  WEB_FEDERATOR_RETRY_QUEUE = 'Pleroma.Web.Federator.RetryQueue',
+  ADMIN_TOKEN = ':admin_token',
+  TWITTER_OAUTH = 'Ueberauth.Strategy.Twitter.OAuth',
+  FACEBOOK_OAUTH = 'Ueberauth.Strategy.Facebook.OAuth',
+  GOOGLE_OAUTH = 'Ueberauth.Strategy.Google.OAuth',
+  MICROSOFT_OAUTH = 'Ueberauth.Strategy.Microsoft.OAuth',
+  MARKUP = ':markup',
+  ESSHD = ':esshd'
+}
+
+export const arrayParams = {
+  [configKeys.INSTANCE]: ['quarantined_instances', 'mrf_transparency_exclusions', 'autofollowed_nicknames'],
+  [configKeys.LDAP]: ['sslopts', 'tlsopts'],
+  [configKeys.MEDIA_PROXY]: ['whitelist'],
+  [configKeys.RICH_MEDIA]: ['ignore_hosts', 'ignore_tld', 'ttl_setters'],
+  [configKeys.GOPHER]: ['ip'],
+  [configKeys.EMOJI]: ['pack_extensions'],
+  [configKeys.ECTO_REPOS]: ['ecto_repos'],
+  [configKeys.MRF_SIMPLE]: [
+    'media_removal',
+    'media_nsfw',
+    'federated_timeline_removal',
+    'reject',
+    'accept',
+    'report_removal',
+    'avatar_removal',
+    'banner_removal'
+  ],
+  [configKeys.MRF_KEYWORD]: ['reject', 'federated_timeline_removal'],
+  [configKeys.MRF_VOCABULARY]: ['accept', 'reject'],
+  [configKeys.WEB_ENDPOINT]: ['instrumenters', 'extra_cookie_attrs', 'watchers'],
+  [configKeys.AUTH]: ['oauth_consumer_strategies'],
+  [configKeys.MARKUP]: ['scrub_policy']
+}
+
+export const normalizerMapper = {
+  [configKeys.AUTO_LINKER]: { normalizer: normalizeAutoLinkerConfig, normalizeBeforeGeneralFunc: true },
+  [configKeys.GOPHER]: { normalizer: normalizeGopherConfig, normalizeBeforeGeneralFunc: true },
+  [configKeys.EMAILS]: { normalizer: normalizeEmailsConfig, normalizeBeforeGeneralFunc: true },
+  [configKeys.ASSETS]: { normalizer: normalizeAssetsConfig, normalizeBeforeGeneralFunc: true },
+  [configKeys.RATE_LIMIT]: { normalizer: normalizeRateLimitConfig, normalizeBeforeGeneralFunc: false },
+  [configKeys.EMOJI]: { normalizer: normalizeEmojiConfig, normalizeBeforeGeneralFunc: false },
+  [configKeys.ECTO_REPOS]: { normalizer: normalizeEctoReposConfig, normalizeBeforeGeneralFunc: false },
+  [configKeys.MRF_SUBCHAIN]: { normalizer: normalizeMRFSubchainConfig, normalizeBeforeGeneralFunc: false },
+  [configKeys.MRF_KEYWORD]: { normalizer: normalizeMrfKeywordConfig, normalizeBeforeGeneralFunc: false },
+  [configKeys.MRF_USER_ALLOWLIST]: { normalizer: normalizeMRFUserAllowlistConfig, normalizeBeforeGeneralFunc: false },
+  [configKeys.WEB_ENDPOINT]: { normalizer: normalizeWebEndpointConfig, normalizeBeforeGeneralFunc: false },
+  [configKeys.ADMIN_TOKEN]: { normalizer: normalizeAdminTokenConfig, normalizeBeforeGeneralFunc: false },
+  [configKeys.WEB_AUTHENTICATOR]: { normalizer: normalizeWebAuthenticatorConfig, normalizeBeforeGeneralFunc: false }
+}
+
+export const getConfigGroup = (configKey) => {
+  const configObj = configKeysTabs.find(({ key }) => key === configKey)
+  // @ts-ignore
+  return configObj.group || configGroups.PLEROMA
+}
+
+export const configKeysTabs = [
+  {
+    key: configKeys.EMAILS,
+    group: configGroups.PLEROMA,
+    tab: true,
+    constructor: EmailsConfig,
+  },
+  {
+    key: configKeys.UPLOAD,
+    group: configGroups.PLEROMA,
+    constructor: UploadConfig,
+    tab: true,
+  },
+  {
+    key: configKeys.UPLOADERSS3,
+    group: configGroups.PLEROMA,
+    tab: false,
+    constructor: UploadersS3Config,
+  },
+  {
+    key: configKeys.UPLOADERSLOCAL,
+    group: configGroups.PLEROMA,
+    tab: false,
+    constructor: UploadersLocalConfig,
+  },
+  {
+    key: configKeys.UPLOADERSMDII,
+    group: configGroups.PLEROMA,
+    tab: false,
+    constructor: UploadersMDIIConfig,
+  },
+  {
+    key: configKeys.INSTANCE,
+    group: configGroups.PLEROMA,
+    constructor: InstanceConfig,
+    tab: true,
+  },
+  {
+    key: configKeys.LOGGER,
+    tab: false,
+    constructor: LoggerConfig,
+  },
+  {
+    key: configKeys.FRONTEND_CONFIGURATIONS,
+    group: configGroups.PLEROMA,
+    constructor: FrontentConfigurationsConfig,
+    tab: true,
+  },
+  {
+    key: configKeys.CHAT,
+    group: configGroups.PLEROMA,
+    tab: false,
+    constructor: ChatConfig,
+  },
+  {
+    key: configKeys.EMOJI,
+    group: configGroups.PLEROMA,
+    tab: false,
+    constructor: EmojiConfig,
+  },
+  {
+    key: configKeys.ASSETS,
+    group: configGroups.PLEROMA,
+    tab: false,
+    constructor: AssetsConfig,
+  },
+  {
+    key: configKeys.WEB_ENDPOINT,
+    group: configGroups.PLEROMA,
+    tab: true,
+    constructor: WebEndpointConfig
+  },
+  {
+    key: configKeys.WEB_METADATA,
+    group: configGroups.PLEROMA,
+    tab: true,
+    constructor: WebMetadataConfig,
+  },
+  {
+    key: configKeys.CAPTCHA,
+    group: configGroups.PLEROMA,
+    constructor: CaptchaConfig,
+    tab: true,
+  },
+  {
+    key: configKeys.KOCAPTCHA,
+    group: configGroups.PLEROMA,
+    tab: false,
+    constructor: KocaptchaConfig
+  },
+  {
+    key: configKeys.URI_SCHEMES,
+    group: configGroups.PLEROMA,
+    constructor: UriSchemesConfig,
+    tab: true,
+  },
+  {
+    key: configKeys.DATABASE,
+    constructor: DatabaseConfig,
+    tab: true,
+  },
+  {
+    key: configKeys.ECTO_REPOS,
+    group: configGroups.PLEROMA,
+    tab: false,
+    constructor: EctoReposConfig,
+  },
+  {
+    key: configKeys.MEDIA_PROXY,
+    group: configGroups.PLEROMA,
+    constructor: MediaProxyConfig,
+    tab: true,
+  },
+  {
+    key: configKeys.GOPHER,
+    group: configGroups.PLEROMA,
+    tab: true,
+    constructor: GopherConfig,
+  },
+  {
+    key: configKeys.LDAP,
+    group: configGroups.PLEROMA,
+    constructor: LdapConfig,
+    tab: false,
+  },
+  {
+    key: configKeys.ACTIVITY_PUB,
+    group: configGroups.PLEROMA,
+    constructor: ActivityPubConfig,
+    tab: true,
+  },
+  {
+    key: configKeys.USER,
+    group: configGroups.PLEROMA,
+    constructor: UserConfig,
+    tab: true,
+  },
+  {
+    key: configKeys.HTTP_SECURITY,
+    group: configGroups.PLEROMA,
+    constructor: HttpSecurityConfig,
+    tab: true,
+  },
+  {
+    key: configKeys.RICH_MEDIA,
+    group: configGroups.PLEROMA,
+    constructor: RichMediaConfig,
+    tab: true,
+  },
+  {
+    key: configKeys.FETCH_INITIAL_POSTS,
+    group: configGroups.PLEROMA,
+    tab: true,
+    constructor: FetchInitialPostsConfig,
+  },
+  {
+    key: configKeys.HACKNEY_POOLS,
+    group: configGroups.PLEROMA,
+    tab: true,
+    constructor: HackneyPoolsConfig,
+  },
+  {
+    key: configKeys.AUTO_LINKER,
+    tab: true,
+    constructor: AutoLinkerConfig,
+  },
+  {
+    key: configKeys.SCHEDULED_ACTIVITY,
+    group: configGroups.PLEROMA,
+    tab: true,
+    constructor: ScheduledActivityConfig,
+  },
+  {
+    key: configKeys.AUTH,
+    tab: true,
+    constructor: AuthConfig
+  },
+  {
+    key: configKeys.WEB_AUTHENTICATOR,
+    tab: false,
+    constructor: WebAuthenticatorConfig
+  },
+  {
+    key: configKeys.TWITTER_OAUTH,
+    group: configGroups.UEBERAUTH,
+    tab: false,
+    constructor: UeberauthTwitterOAuth
+  },
+  {
+    key: configKeys.FACEBOOK_OAUTH,
+    group: configGroups.UEBERAUTH,
+    tab: false,
+    constructor: UeberauthFacebookOAuth
+  },
+  {
+    key: configKeys.GOOGLE_OAUTH,
+    group: configGroups.UEBERAUTH,
+    tab: false,
+    constructor: UeberauthGoogleOAuth
+  },
+  {
+    key: configKeys.MICROSOFT_OAUTH,
+    group: configGroups.UEBERAUTH,
+    tab: false,
+    constructor: UeberauthMicrosoftOAuth
+  },
+  {
+    key: configKeys.ADMIN_TOKEN,
+    tab: false,
+    constructor: AdminTokenConfig
+  },
+  {
+    key: configKeys.OAUTH2,
+    group: configGroups.PLEROMA,
+    tab: false,
+    constructor: Oauth2Config,
+  },
+  {
+    key: configKeys.RATE_LIMIT,
+    group: configGroups.PLEROMA,
+    tab: true,
+    constructor: RateLimitConfig,
+  },
+  {
+    key: configKeys.MRF_SIMPLE,
+    group: configGroups.PLEROMA,
+    tab: true,
+    constructor: MRFSimple,
+  },
+  {
+    key: configKeys.MRF_SUBCHAIN,
+    group: configGroups.PLEROMA,
+    tab: false,
+    constructor: MRFSubchainConfig,
+  },
+  {
+    key: configKeys.MRF_REJECTNONPUBLIC,
+    group: configGroups.PLEROMA,
+    tab: false,
+    constructor: MRFRejectnonpublic,
+  },
+  {
+    key: configKeys.MRF_HELLTHREAD,
+    group: configGroups.PLEROMA,
+    tab: false,
+    constructor: MRFHellthread,
+  },
+  {
+    key: configKeys.MRF_KEYWORD,
+    group: configGroups.PLEROMA,
+    tab: false,
+    constructor: MRFKeyword,
+  },
+  {
+    key: configKeys.MRF_MENTION,
+    tab: false,
+    constructor: MRFMention,
+  },
+  {
+    key: configKeys.MRF_USER_ALLOWLIST,
+    tab: false,
+    constructor: MRFUserAllowlist,
+  },
+  {
+    key: configKeys.MRF_NORMALIZE_MARKUP,
+    group: configGroups.PLEROMA,
+    tab: false,
+    constructor: MRFNormalizeMarkupConfig,
+  },
+  {
+    key: configKeys.MRF_VOCABULARY,
+    group: configGroups.PLEROMA,
+    tab: false,
+    constructor: MrfVocabularyConfig,
+  },
+  {
+    key: configKeys.SUGGESTIONS,
+    group: configGroups.PLEROMA,
+    tab: true,
+    constructor: SuggestionsConfig,
+  },
+  {
+    key: configKeys.VAPID_DETAILS,
+    group: configGroups.PUSH_ENCRYPTION,
+    tab: true,
+    constructor: VapidDetailsConfig,
+  },
+  {
+    key: configKeys.JOB_QUEUE,
+    group: configGroups.PLEROMA_JOB_QUEUE,
+    tab: true,
+    constructor: JobQueueConfig,
+  },
+  {
+    key: configKeys.WEB_FEDERATOR_RETRY_QUEUE,
+    group: configGroups.PLEROMA,
+    tab: false,
+    constructor: WebFederationQueueConfig,
+  },
+  {
+    key: configKeys.MARKUP,
+    group: configGroups.PLEROMA,
+    tab: false,
+    constructor: MarkupConfig
+  },
+  {
+    key: configKeys.ESSHD,
+    group: configGroups.PLEROMA,
+    tab: true,
+    constructor: EsshdConfig
+  }
+]
diff --git a/src/entities/settings/ActivityPubConfig.ts b/src/entities/settings/ActivityPubConfig.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c75f8aa8a9c9abb065eb33f585721bda3351c4cc
--- /dev/null
+++ b/src/entities/settings/ActivityPubConfig.ts
@@ -0,0 +1,12 @@
+import {normalizeApiConfig} from "../../utils/ConvertConfigToState";
+
+export default class ActivityPubConfig {
+  constructor(existConfig?) {
+    normalizeApiConfig(existConfig, this)
+  }
+  accept_blocks: boolean = true
+  unfollow_blocked: boolean = true
+  outgoing_blocks: boolean = true
+  follow_handshake_timeout: number = 500
+  sign_object_fetches: boolean = true
+}
diff --git a/src/entities/settings/AdminTokenConfig.ts b/src/entities/settings/AdminTokenConfig.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ec88c96d15b5ae59b2bfb56aa2632c734ab1135d
--- /dev/null
+++ b/src/entities/settings/AdminTokenConfig.ts
@@ -0,0 +1,10 @@
+export default class AdminTokenConfig {
+  constructor(existConfig?) {
+    this.token = existConfig || ''
+  }
+  token: string = ''
+}
+
+export const normalizeAdminTokenConfig = (config) => {
+  return config[0].tuple[1]
+}
diff --git a/src/entities/settings/AssetsConfig.ts b/src/entities/settings/AssetsConfig.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c93e82333596e44076b85dfc8cfe5674e67490ad
--- /dev/null
+++ b/src/entities/settings/AssetsConfig.ts
@@ -0,0 +1,30 @@
+import { normalizeApiConfig } from '../../utils/ConvertConfigToState'
+import { forIn } from 'lodash'
+
+export default class AssetsConfig {
+  constructor(existConfig? ){
+    normalizeApiConfig(existConfig, this)
+    if (existConfig) {
+      const mascots = existConfig.find(({ tuple }) => tuple[0] === ':mascots').tuple[1]
+      this.mascots = mascots.map(({ tuple }) => ({
+          name: tuple[0],
+          mime_type: tuple[1].mime_type,
+          url: tuple[1].url
+        })
+      )
+    }
+  }
+  mascots: Array<any> = []
+  default_mascot: string = ''
+}
+
+export const normalizeAssetsConfig = (config) => {
+  const apiConfig = { ...config }
+  const newMascots = []
+  forIn(apiConfig.mascots, ({ name, mime_type, url }) => {
+    // @ts-ignore
+    newMascots.push({tuple: [name, {':mime_type': mime_type, ':url': url}]})
+  })
+  apiConfig.mascots = newMascots
+  return apiConfig
+}
diff --git a/src/entities/settings/AuthConfig.ts b/src/entities/settings/AuthConfig.ts
new file mode 100644
index 0000000000000000000000000000000000000000..59f165d5cb6543fdc316d84ff20b7e80af6f0147
--- /dev/null
+++ b/src/entities/settings/AuthConfig.ts
@@ -0,0 +1,11 @@
+import { normalizeApiConfig } from '../../utils/ConvertConfigToState'
+import {arrayParams, configKeys} from '../../data/Config'
+
+export default class AuthConfig {
+  constructor(existConfig?) {
+    normalizeApiConfig(existConfig, this, arrayParams[configKeys.AUTH])
+  }
+  oauth_consumer_strategies: any = []
+  auth_template: string = ''
+  oauth_consumer_template: string = ''
+}
diff --git a/src/entities/settings/AutoLinkerConfig.ts b/src/entities/settings/AutoLinkerConfig.ts
new file mode 100644
index 0000000000000000000000000000000000000000..614a1f6337ac01cbd5380880c01908ba79f04485
--- /dev/null
+++ b/src/entities/settings/AutoLinkerConfig.ts
@@ -0,0 +1,49 @@
+import { normalizeApiConfig } from '../../utils/ConvertConfigToState'
+import t from 'typy'
+
+export default class AutoLinkerConfig {
+  constructor(existConfig?) {
+    normalizeApiConfig(existConfig, this)
+    if (t(this.opts, 'class').safeObject) {
+      this.class_text = t(this.opts, 'class').safeObject
+      this.opts['class'] = true
+    }
+    if (t(this.opts, 'strip_prefix').safeObject) {
+      this.strip_prefix_text = t(this.opts, 'strip_prefix').safeObject
+      this.opts['strip_prefix'] = true
+    }
+  }
+
+  opts: object = {
+    scheme: true,
+    extra: true,
+    validate_tld: true,
+    class: false,
+    strip_prefix: false,
+    new_window: false,
+    rel: false,
+    sendAsMap: true
+  }
+  class_text: string = ''
+  strip_prefix_text: string = ''
+}
+
+export const normalizeAutoLinkerConfig = (config) => {
+  const apiConf = {...config}
+
+  if (apiConf.opts.class && apiConf.class_text.length) {
+    apiConf.opts.class = apiConf.class_text
+  } else {
+    apiConf.opts.class = false
+  }
+  delete apiConf.class_text
+
+  if (apiConf.opts.strip_prefix && apiConf.strip_prefix_text.length) {
+    apiConf.opts.strip_prefix = apiConf.strip_prefix_text
+  } else {
+    apiConf.opts.strip_prefix = false
+  }
+  delete apiConf.strip_prefix_text
+
+  return apiConf
+}
diff --git a/src/entities/settings/CaptchaConfig.ts b/src/entities/settings/CaptchaConfig.ts
new file mode 100644
index 0000000000000000000000000000000000000000..2666eb06ff921d5333fca1156158a1d9bf7266c4
--- /dev/null
+++ b/src/entities/settings/CaptchaConfig.ts
@@ -0,0 +1,10 @@
+import {normalizeApiConfig} from "../../utils/ConvertConfigToState";
+
+export default class CaptchaConfig {
+  constructor(existConfig?) {
+    normalizeApiConfig(existConfig, this)
+  }
+  enabled: boolean = false
+  method: string = 'Pleroma.Captcha.Kocaptcha'
+  seconds_valid?: number
+}
diff --git a/src/entities/settings/ChatConfig.ts b/src/entities/settings/ChatConfig.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5da0e7e49741c911e8453f945265752f54b23c7f
--- /dev/null
+++ b/src/entities/settings/ChatConfig.ts
@@ -0,0 +1,8 @@
+import { normalizeApiConfig } from '../../utils/ConvertConfigToState'
+
+export default class ChatConfig {
+  constructor(existConfig?) {
+    normalizeApiConfig(existConfig, this)
+  }
+  enabled: boolean = true
+}
diff --git a/src/entities/settings/DatabaseConfig.ts b/src/entities/settings/DatabaseConfig.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5d94cb31547e6e33355fb5f65f88b250b2c676aa
--- /dev/null
+++ b/src/entities/settings/DatabaseConfig.ts
@@ -0,0 +1,8 @@
+import { normalizeApiConfig } from '../../utils/ConvertConfigToState'
+
+export default class DatabaseConfig {
+  constructor(existConfig?) {
+    normalizeApiConfig(existConfig, this)
+  }
+  rum_enabled: boolean = false
+}
diff --git a/src/entities/settings/EctoReposConfig.ts b/src/entities/settings/EctoReposConfig.ts
new file mode 100644
index 0000000000000000000000000000000000000000..0d3d0d0cb6f06d401c10391244c98abebf7fac7c
--- /dev/null
+++ b/src/entities/settings/EctoReposConfig.ts
@@ -0,0 +1,12 @@
+import { convertArrayParamsToState } from '../../utils/ConvertConfigToState'
+import { arrayParams, configKeys } from '../../data/Config'
+
+export default class EctoReposConfig {
+  constructor(existConfig?) {
+    this.ecto_repos = [...existConfig]
+    convertArrayParamsToState(this, arrayParams[configKeys.ECTO_REPOS])
+  }
+  ecto_repos: any = ''
+}
+
+export const normalizeEctoReposConfig = (config) => ([...config[0].tuple[1]])
diff --git a/src/entities/settings/EmailsConfig.ts b/src/entities/settings/EmailsConfig.ts
new file mode 100644
index 0000000000000000000000000000000000000000..67758212a63a81dc396e158cce832ea550d27dbb
--- /dev/null
+++ b/src/entities/settings/EmailsConfig.ts
@@ -0,0 +1,51 @@
+import { normalizeApiConfig } from '../../utils/ConvertConfigToState'
+import t from 'typy'
+import { forEach } from 'lodash'
+import {getFieldComponent} from "../../utils/GetFieldList";
+
+export class AdapterOption {
+  constructor(options?) {
+    if (options) {
+      this.type = options.type || { component: 'va-input' }
+      switch (t(options, 'type.component').safeObject) {
+        case 'va-checkbox': {
+          this.value = options.value ? options.value : true
+          break
+        }
+        case 'va-input': {
+          this.value = options.value ? options.value : t(options, 'type.isNumber').safeObject ? 0 : ''
+        }
+      }
+      this.name = options.name ? options.name : ''
+    }
+  }
+  name: any = ''
+  value: any = ''
+  type: any = { component: 'va-input' }
+}
+export default class EmailsConfig {
+  constructor (existConfig? ){
+    normalizeApiConfig(existConfig, this)
+    forEach(existConfig, ({ tuple }) => {
+      const key = tuple[0].substring(1)
+      const value = tuple[1]
+      if (key !== 'adapter' && key !== 'enabled') {
+        this.adapterOptions.push(new AdapterOption({ type: getFieldComponent(value), value, name: key }))
+      }
+    })
+  }
+  adapter: string = ''
+  enabled: boolean = false
+  adapterOptions: Array<AdapterOption>= []
+}
+
+export const normalizeEmailsConfig = (config) => {
+  const apiConf = { ...config }
+  apiConf.adapterOptions
+    .filter(({ name, value }) => name.length)
+    .forEach(({ name, value }) => {
+      apiConf[name] = value
+    })
+  delete apiConf.adapterOptions
+  return apiConf
+}
diff --git a/src/entities/settings/EmojiConfig.ts b/src/entities/settings/EmojiConfig.ts
new file mode 100644
index 0000000000000000000000000000000000000000..7f042d43719fe90ade71b3788a551b22e3e1d3c8
--- /dev/null
+++ b/src/entities/settings/EmojiConfig.ts
@@ -0,0 +1,35 @@
+import { normalizeApiConfig } from '../../utils/ConvertConfigToState'
+import { forIn } from 'lodash'
+import {arrayParams, configKeys} from '../../data/Config'
+
+export default class EmojiConfig {
+  constructor(existConfig?) {
+    if (existConfig) {
+      const groups = existConfig.find(({ tuple }) => tuple[0] === ':groups')
+      const newGroupsList:any = []
+      groups.tuple[1].forEach(({ tuple }) => {
+        tuple[1] = tuple[1].join(';')
+        newGroupsList.push(tuple)
+      })
+      groups.tuple[1] = newGroupsList
+    }
+    normalizeApiConfig(existConfig, this, arrayParams[configKeys.EMOJI])
+  }
+  shortcode_globs: any = []
+  pack_extensions: any = []
+  default_manifest: string = 'https://git.pleroma.social/pleroma/emoji-index/raw/master/index.json'
+  groups: any = []
+}
+
+export const normalizeEmojiConfig = (config) => {
+  const apiConfig = [...config]
+  const groups = apiConfig.find(({ tuple }) => tuple[0] === ':groups')
+  groups.tuple[1] = groups.tuple[1].map(group => {
+    if (group[0].length && group[1].length) {
+      return { tuple: [ group[0], group[1].split(';')] }
+    }
+  }).filter(group => group)
+  const shortcode_globs = apiConfig.find(({ tuple }) => tuple[0] === ':shortcode_globs')
+  shortcode_globs.tuple[1] = shortcode_globs.tuple[1].filter(globe => globe.length)
+  return apiConfig
+}
diff --git a/src/entities/settings/EsshdConfig.ts b/src/entities/settings/EsshdConfig.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f3efc7735d186aecbe92830886a649f007a4ddae
--- /dev/null
+++ b/src/entities/settings/EsshdConfig.ts
@@ -0,0 +1,12 @@
+import {normalizeApiConfig} from '../../utils/ConvertConfigToState'
+
+export default class EsshdConfig {
+  constructor(existConfig?){
+    normalizeApiConfig(existConfig, this)
+  }
+  enabled: boolean = false
+  priv_dir: string = ''
+  handler: string = ''
+  port: number = 10022
+  password_authenticator: string = 'Pleroma.BBS.Authenticator'
+}
diff --git a/src/entities/settings/FetchInitialPostsConfig.ts b/src/entities/settings/FetchInitialPostsConfig.ts
new file mode 100644
index 0000000000000000000000000000000000000000..88939ee66ad61204fbbd54e64aec565d4c1bd121
--- /dev/null
+++ b/src/entities/settings/FetchInitialPostsConfig.ts
@@ -0,0 +1,9 @@
+import { normalizeApiConfig } from '../../utils/ConvertConfigToState'
+
+export default class FetchInitialPostsConfig {
+  constructor(existConfig?) {
+    normalizeApiConfig(existConfig, this)
+  }
+  enabled: boolean = false
+  pages: number = 5
+}
diff --git a/src/entities/settings/FrontentConfigurationsConfig.ts b/src/entities/settings/FrontentConfigurationsConfig.ts
new file mode 100644
index 0000000000000000000000000000000000000000..28e160d641e679f5e07db10b6bda562e21c78639
--- /dev/null
+++ b/src/entities/settings/FrontentConfigurationsConfig.ts
@@ -0,0 +1,31 @@
+import { normalizeApiConfig } from '../../utils/ConvertConfigToState'
+
+export default class FrontentConfigurationsConfig {
+  constructor(existConfig?) {
+    // debugger;
+    normalizeApiConfig(existConfig, this)
+  }
+  pleroma_fe: object = {
+    theme: 'pleroma-dark',
+    logo: '/static/logo.png',
+    background: '/images/city.jpg',
+    redirectRootNoLogin: '/main/all',
+    redirectRootLogin: '/main/friends',
+    hidePostStats: false,
+    hideUserStats: false,
+    collapseMessageWithSubject: false,
+    showInstanceSpecificPanel: true,
+    scopeOptionsEnabled: false,
+    formattingOptionsEnabled: false,
+    scopeCopy: true,
+    alwaysShowSubjectInput: true,
+    subjectLineBehavior: "email",
+    sendAsMap: true,
+  }
+  masto_fe: object = {
+    showInstanceSpecificPanel: true,
+    sendAsMap: true,
+  }
+  // logo_mask:boolean = false
+  // logo_margin?: number
+}
diff --git a/src/entities/settings/GopherConfig.ts b/src/entities/settings/GopherConfig.ts
new file mode 100644
index 0000000000000000000000000000000000000000..44b2f415b9d44bd2f820b70c130d4850994323ee
--- /dev/null
+++ b/src/entities/settings/GopherConfig.ts
@@ -0,0 +1,24 @@
+import {normalizeApiConfig} from '../../utils/ConvertConfigToState'
+import {arrayParams, configKeys} from '../../data/Config'
+
+export default class GopherConfig {
+  constructor(existConfig?) {
+    if (existConfig) {
+      const ip = existConfig.find(({ tuple }) => tuple[0] === ':ip')
+      if (ip) {
+        ip.tuple[1] = ip.tuple[1].tuple
+      }
+    }
+    normalizeApiConfig(existConfig, this, arrayParams[configKeys.GOPHER])
+  }
+  enabled: boolean = false
+  ip: any = '0000'
+  port: number = 9999
+}
+
+
+export const normalizeGopherConfig = (config) => {
+  const apiConf = {...config}
+  apiConf.ip = { tuple: apiConf.ip, sendAsMap: true}
+  return apiConf
+}
diff --git a/src/entities/settings/HackneyPoolsConfig.ts b/src/entities/settings/HackneyPoolsConfig.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c472cb0c480a3697b26bdfb89c24789037813b67
--- /dev/null
+++ b/src/entities/settings/HackneyPoolsConfig.ts
@@ -0,0 +1,19 @@
+import { normalizeApiConfig } from '../../utils/ConvertConfigToState'
+
+export default class HackneyPoolsConfig {
+  constructor(existConfig?) {
+    normalizeApiConfig(existConfig, this)
+  }
+  federation: any = {
+    max_connections: 50,
+    timeout: 1500000
+  }
+  media: any = {
+    max_connections: 50,
+    timeout: 1500000
+  }
+  upload: any = {
+    max_connections: 26,
+    timeout: 300000
+  }
+}
diff --git a/src/entities/settings/HttpSecurityConfig.ts b/src/entities/settings/HttpSecurityConfig.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ff045008cf1c7730c9db3325984399fe95f140fa
--- /dev/null
+++ b/src/entities/settings/HttpSecurityConfig.ts
@@ -0,0 +1,12 @@
+import { normalizeApiConfig } from '../../utils/ConvertConfigToState'
+
+export default class HttpSecurityConfig {
+  constructor(existConfig?) {
+    normalizeApiConfig(existConfig, this)
+  }
+  enabled: boolean = true
+  sts: boolean = false
+  sts_max_age: number = 31536000
+  ct_max_age: number = 2592000
+  referrer_policy: string = 'same-origin'
+}
diff --git a/src/entities/settings/InstanceConfig.ts b/src/entities/settings/InstanceConfig.ts
new file mode 100644
index 0000000000000000000000000000000000000000..92e3dd2cad6e5fbe0dfcc887921cb1ee7248f672
--- /dev/null
+++ b/src/entities/settings/InstanceConfig.ts
@@ -0,0 +1,60 @@
+import { normalizeApiConfig } from '../../utils/ConvertConfigToState'
+import { configKeys, arrayParams } from '../../data/Config'
+
+export default class InstanceConfig {
+  constructor(existConfig?) {
+    normalizeApiConfig(
+      existConfig,
+      this,
+      arrayParams[configKeys.INSTANCE]
+    )
+  }
+  name: string = ''
+  email: string = ''
+  notify_email: string = ''
+  description: string = ''
+  limit: number = 5000
+  remote_limit?: number
+  upload_limit: string = ''
+  avatar_upload_limit: string = ''
+  background_upload_limit: string = ''
+  banner_upload_limit: string = ''
+  poll_limits: object = {
+    max_options:  20,
+    max_option_chars: 200,
+    min_expiration: 0,
+    max_expiration: 31536000,
+    sendAsMap: true
+  }
+  registrations_open: boolean = false
+  invites_enabled: boolean = false
+  account_activation_required: boolean = false
+  federating: boolean = false
+  federation_reachability_timeout_days: number = 1
+  federation_incoming_replies_max_depth: number = 100
+  federation_publisher_modules: Array<string> = [ 'Pleroma.Web.ActivityPub.Publisher', 'Pleroma.Web.Websub', 'Pleroma.Web.Salmon']
+  allow_relay: boolean = false
+  rewrite_policy: Array<string> = []
+  public: boolean = false
+  quarantined_instances: any = ''
+  managed_config: boolean = false
+  static_dir: string = 'instance/static'
+  allowed_post_formats: Array<string> = []
+  mrf_transparency: boolean = false
+  mrf_transparency_exclusions: any = []
+  extended_nickname_format: boolean = false
+  max_pinned_statuses?: number
+  autofollowed_nicknames: any = ''
+  no_attachment_links: boolean = false
+  welcome_message: string = ''
+  welcome_user_nickname: string = ''
+  max_report_comment_size?: number
+  safe_dm_mentions: boolean = false
+  healthcheck: boolean = false
+  remote_post_retention_days?: number
+  skip_thread_containment: boolean = false
+  limit_to_local_content: string = ':unauthenticated'
+  external_user_synchronization: boolean = true
+  dynamic_configuration: boolean = false
+  sendAsMap: boolean = true
+}
diff --git a/src/entities/settings/JobQueueConfig.ts b/src/entities/settings/JobQueueConfig.ts
new file mode 100644
index 0000000000000000000000000000000000000000..4ebdf0529cdf993ac1afe2a4283428f3ed4c7d5f
--- /dev/null
+++ b/src/entities/settings/JobQueueConfig.ts
@@ -0,0 +1,13 @@
+import { normalizeApiConfig } from '../../utils/ConvertConfigToState'
+
+export default class JobQueueConfig {
+  constructor(existConfig?) {
+    normalizeApiConfig(existConfig, this)
+  }
+  federator_outgoing: number = 0
+  federator_incoming: number = 0
+  mailer: string = ''
+  transmogrifier: number = 0
+  web_push: boolean = false
+  scheduled_activities: string = ''
+}
diff --git a/src/entities/settings/KocaptchaConfig.ts b/src/entities/settings/KocaptchaConfig.ts
new file mode 100644
index 0000000000000000000000000000000000000000..95227f1bed33bdfc02bc154e0d7a9bfce4ddae4b
--- /dev/null
+++ b/src/entities/settings/KocaptchaConfig.ts
@@ -0,0 +1,8 @@
+import {normalizeApiConfig} from "../../utils/ConvertConfigToState";
+
+export default class KocaptchaConfig {
+  constructor(existConfig?) {
+    normalizeApiConfig(existConfig, this)
+  }
+  endpoint: string = 'https://captcha.kotobank.ch'
+}
diff --git a/src/entities/settings/LdapConfig.ts b/src/entities/settings/LdapConfig.ts
new file mode 100644
index 0000000000000000000000000000000000000000..4680c20a6f9a93aac6cc2f6d372b93e1227be020
--- /dev/null
+++ b/src/entities/settings/LdapConfig.ts
@@ -0,0 +1,21 @@
+import { normalizeApiConfig } from '../../utils/ConvertConfigToState'
+import { configKeys, arrayParams } from '../../data/Config'
+
+export default class LdapConfig {
+  constructor (existConfig?) {
+    normalizeApiConfig(
+      existConfig,
+      this,
+      arrayParams[configKeys.LDAP]
+    )
+  }
+  enabled: boolean = false
+  host: string = 'localhost'
+  port: number = 389
+  ssl: boolean = false
+  sslopts: any = ''
+  tls: number = 389
+  tlsopts: any = ''
+  base: string = 'dc=example,dc=com'
+  uid: string = 'cn'
+}
diff --git a/src/entities/settings/LoggerConfig.ts b/src/entities/settings/LoggerConfig.ts
new file mode 100644
index 0000000000000000000000000000000000000000..418e4f91add1459c21e006923b432f4b34c2afa8
--- /dev/null
+++ b/src/entities/settings/LoggerConfig.ts
@@ -0,0 +1,8 @@
+import {normalizeApiConfig} from '../../utils/ConvertConfigToState'
+
+export default class LoggerConfig {
+  constructor(existConfig?: any) {
+    normalizeApiConfig(existConfig, this)
+  }
+
+}
diff --git a/src/entities/settings/MRFHellthread.ts b/src/entities/settings/MRFHellthread.ts
new file mode 100644
index 0000000000000000000000000000000000000000..638c241b4b75857d662f5984c4ac25e95a938040
--- /dev/null
+++ b/src/entities/settings/MRFHellthread.ts
@@ -0,0 +1,9 @@
+import { normalizeApiConfig } from '../../utils/ConvertConfigToState'
+
+export default class MRFHellthread {
+  constructor(existConfig?) {
+    normalizeApiConfig(existConfig, this)
+  }
+  delist_threshold: number = 0
+  reject_threshold: number = 0
+}
diff --git a/src/entities/settings/MRFKeyword.ts b/src/entities/settings/MRFKeyword.ts
new file mode 100644
index 0000000000000000000000000000000000000000..91b084efd45477941efcd2205997c45e5085fc21
--- /dev/null
+++ b/src/entities/settings/MRFKeyword.ts
@@ -0,0 +1,25 @@
+import { normalizeApiConfig } from '../../utils/ConvertConfigToState'
+import { arrayParams, configKeys } from '../../data/Config'
+
+export class ReplaceItemClass {
+  pattern: string = ''
+  replacement: string = ''
+}
+
+export default class MRFKeyword {
+  constructor(existConfig?) {
+    normalizeApiConfig(existConfig, this, arrayParams[configKeys.MRF_KEYWORD])
+  }
+  reject: any = ''
+  federated_timeline_removal: any = ''
+  replace: Array<ReplaceItemClass> = [new ReplaceItemClass()]
+}
+
+export const normalizeMrfKeywordConfig = (config) => {
+  const apiConf = [ ...config ]
+  const replaceIndex = apiConf.findIndex(({ tuple }) => tuple[0] === ':replace')
+  apiConf[replaceIndex].tuple[1] = apiConf[replaceIndex].tuple[1]
+    .filter(({ pattern }) => !!pattern.length)
+    .map(({ pattern , replacement }) => ({ tuple: [pattern, replacement]}))
+  return apiConf
+}
diff --git a/src/entities/settings/MRFMention.ts b/src/entities/settings/MRFMention.ts
new file mode 100644
index 0000000000000000000000000000000000000000..a80d85cb8ec4371bbaa8bec5a85cd5838ddce25f
--- /dev/null
+++ b/src/entities/settings/MRFMention.ts
@@ -0,0 +1,8 @@
+import {normalizeApiConfig} from "../../utils/ConvertConfigToState";
+
+export default class MRFMention {
+  constructor(existConfig?) {
+    normalizeApiConfig(existConfig, this)
+  }
+  actors: any = ''
+}
diff --git a/src/entities/settings/MRFNormalizeMarkupConfig.ts b/src/entities/settings/MRFNormalizeMarkupConfig.ts
new file mode 100644
index 0000000000000000000000000000000000000000..0bac1771d161751eab07e06c354c7c5021a1c505
--- /dev/null
+++ b/src/entities/settings/MRFNormalizeMarkupConfig.ts
@@ -0,0 +1,8 @@
+import { normalizeApiConfig } from '../../utils/ConvertConfigToState'
+
+export default class MRFNormalizeMarkupConfig {
+  constructor(existConfig?) {
+    normalizeApiConfig(existConfig, this)
+  }
+  scrub_policy:string = ''
+}
diff --git a/src/entities/settings/MRFRejectnonpublic.ts b/src/entities/settings/MRFRejectnonpublic.ts
new file mode 100644
index 0000000000000000000000000000000000000000..007125e5b4d8fcfc1ee6e77d040429c431ce1075
--- /dev/null
+++ b/src/entities/settings/MRFRejectnonpublic.ts
@@ -0,0 +1,9 @@
+import { normalizeApiConfig } from '../../utils/ConvertConfigToState'
+
+export default class MRFRejectnonpublic {
+  constructor(existConfig?) {
+    normalizeApiConfig(existConfig, this)
+  }
+  allow_followersonly: boolean = false
+  allow_direct: boolean = false
+}
diff --git a/src/entities/settings/MRFSimple.ts b/src/entities/settings/MRFSimple.ts
new file mode 100644
index 0000000000000000000000000000000000000000..618b7289a6ddb0ce8a6bf6d891446cec1a8ff125
--- /dev/null
+++ b/src/entities/settings/MRFSimple.ts
@@ -0,0 +1,16 @@
+import { normalizeApiConfig } from '../../utils/ConvertConfigToState'
+import {arrayParams, configKeys} from '../../data/Config'
+
+export default class MRFSimple {
+  constructor(existConfig?) {
+    normalizeApiConfig(existConfig, this, arrayParams[configKeys.MRF_SIMPLE])
+  }
+  media_removal: any = ''
+  media_nsfw: any = ''
+  federated_timeline_removal: any = ''
+  reject: any = ''
+  accept: any = ''
+  report_removal: any = ''
+  avatar_removal: any = ''
+  banner_removal: any = ''
+}
diff --git a/src/entities/settings/MRFSubchainConfig.ts b/src/entities/settings/MRFSubchainConfig.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c0538bd2c6e2c3e4643a2a021223c94ca2dc78a2
--- /dev/null
+++ b/src/entities/settings/MRFSubchainConfig.ts
@@ -0,0 +1,22 @@
+export class MatchActor {
+  constructor(data?) {
+    this.regular_expression = data ? data.regular_expression : ''
+    this.policy_modules = data ? data.policy_modules : ''
+  }
+  regular_expression: string = ''
+  policy_modules: string = ''
+}
+
+export default class MRFSubchainConfig {
+  match_actor: Array<MatchActor> = [new MatchActor()]
+}
+
+export const normalizeMRFSubchainConfig = (config) => {
+  const apiConf = [...config ]
+  apiConf[0].tuple[1] = apiConf[0].tuple[1].filter(item => {
+    return !!item.regular_expression.length
+  }).map(({ regular_expression, policy_modules}) => {
+    return {[regular_expression]: [...policy_modules]}
+  })
+  return apiConf
+}
diff --git a/src/entities/settings/MRFUserAllowlistConfig.ts b/src/entities/settings/MRFUserAllowlistConfig.ts
new file mode 100644
index 0000000000000000000000000000000000000000..031e25ef599975410934587efb3176347da8de8f
--- /dev/null
+++ b/src/entities/settings/MRFUserAllowlistConfig.ts
@@ -0,0 +1,21 @@
+import { normalizeApiConfig } from '../../utils/ConvertConfigToState'
+
+export class UserAllowListItem {
+  domain: string = ''
+  list_of_users: string = ''
+}
+
+export default class MRFUserAllowlistConfig {
+  constructor(existConfig?) {
+    normalizeApiConfig(existConfig, this)
+  }
+  allow_list: Array<UserAllowListItem> = [new UserAllowListItem()]
+}
+
+export const normalizeMRFUserAllowlistConfig = (config) => {
+  let apiConf = [...config]
+  apiConf = apiConf[0].tuple[1]
+    .filter(({ domain }) => !!domain.length)
+    .map(item => ({ tuple: {[item.domain]: item.list_of_users.split(';')}}))
+  return apiConf
+}
diff --git a/src/entities/settings/MarkupConfig.ts b/src/entities/settings/MarkupConfig.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8db86d25f0c4b6b8b42547d953217c0725fc8977
--- /dev/null
+++ b/src/entities/settings/MarkupConfig.ts
@@ -0,0 +1,13 @@
+import {normalizeApiConfig} from '../../utils/ConvertConfigToState'
+import {arrayParams, configKeys} from '../../data/Config'
+
+export default class MarkupConfig {
+  constructor(existConfig?) {
+    normalizeApiConfig(existConfig, this, arrayParams[configKeys.MARKUP])
+  }
+  allow_inline_images: boolean = true
+  allow_headings: boolean = false
+  allow_tables: boolean = false
+  allow_fonts: boolean = false
+  scrub_policy: any = 'Pleroma.HTML.Transform.MediaProxy;Pleroma.HTML.Scrubber.Default'
+}
diff --git a/src/entities/settings/MediaProxyConfig.ts b/src/entities/settings/MediaProxyConfig.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f528c2fcad716709be9ea13ce3d851a462dfb1c5
--- /dev/null
+++ b/src/entities/settings/MediaProxyConfig.ts
@@ -0,0 +1,14 @@
+import { normalizeApiConfig } from '../../utils/ConvertConfigToState'
+import { ReverseProxy } from './UploadConfig'
+import { configKeys, arrayParams } from '../../data/Config'
+
+
+export default class MediaProxyConfig {
+  constructor(existConfig?) {
+    normalizeApiConfig(existConfig, this, arrayParams[configKeys.MEDIA_PROXY])
+  }
+  proxy_opts?: ReverseProxy = new ReverseProxy()
+  base_url: string = ''
+  whitelist: any = ''
+  enabled: boolean = false
+}
diff --git a/src/entities/settings/MrfVocabularyConfig.ts b/src/entities/settings/MrfVocabularyConfig.ts
new file mode 100644
index 0000000000000000000000000000000000000000..42ab2c35a4c39598860796509a0634ba68ae3ad5
--- /dev/null
+++ b/src/entities/settings/MrfVocabularyConfig.ts
@@ -0,0 +1,10 @@
+import {normalizeApiConfig} from '../../utils/ConvertConfigToState'
+import {arrayParams, configKeys} from '../../data/Config'
+
+export default class MrfVocabularyConfig {
+  constructor(existConfig?){
+    normalizeApiConfig(existConfig, this, arrayParams[configKeys.MRF_VOCABULARY])
+  }
+  accept: any = ''
+  reject: any = ''
+}
diff --git a/src/entities/settings/Oauth2Config.ts b/src/entities/settings/Oauth2Config.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8388156eafd4cf7c99d339db31fd3bda9827e655
--- /dev/null
+++ b/src/entities/settings/Oauth2Config.ts
@@ -0,0 +1,11 @@
+import { normalizeApiConfig } from '../../utils/ConvertConfigToState'
+
+export default class Oauth2Config {
+  constructor(existConfig?) {
+    normalizeApiConfig(existConfig, this)
+  }
+  token_expires_in:number = 600
+  issue_new_refresh_token:boolean = true
+  clean_expired_tokens:boolean = false
+  clean_expired_tokens_interval:number = 86400000
+}
diff --git a/src/entities/settings/RateLimitConfig.ts b/src/entities/settings/RateLimitConfig.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f05f6554dc1d75ae5d75cc2ba3d303e589ff914b
--- /dev/null
+++ b/src/entities/settings/RateLimitConfig.ts
@@ -0,0 +1,57 @@
+import t from 'typy'
+import { forIn } from 'lodash'
+
+export default class RateLimitConfig {
+  constructor(existConfig?) {
+    if (existConfig) {
+      existConfig.forEach(({ tuple }) => {
+        const name = tuple[0].substring(1)
+        if (name !== 'search') {
+          const fieldConfig = t(tuple[1], 'tuple').safeObject
+          if (fieldConfig[0]) {
+            this[name].scale = fieldConfig[0]
+          }
+          if (fieldConfig[1]) {
+            this[name].limit = fieldConfig[1]
+          }
+        } else {
+          tuple[1].forEach((search, ind) => {
+            const name = ind === 0 ? 'account' : 'status'
+            const val = search.tuple
+            if (val[0]) {
+              this.search[name].scale = val[0]
+            }
+            if (val[1]) {
+              this.search[name].limit = val[1]
+            }
+          })
+        }
+      })
+    }
+  }
+  search:any = {
+    account: { scale: 1000, limit: 10 },
+    status: { scale: 1000, limit: 30 }
+  }
+  app_account_creation:any = {scale: 1800000, limit: 25}
+  relations_actions:any = {scale: 10000, limit: 10}
+  relation_id_action:any = {scale: 60000, limit: 2}
+  statuses_actions:any = {scale: 10000, limit: 15}
+  status_id_action:any = {scale: 60000, limit: 3}
+  password_reset:any = {scale: 1800000, limit: 5}
+}
+
+
+export const normalizeRateLimitConfig = (config) => {
+  let apiConf = []
+  forIn(config, (field, key) => {
+    if (key !== 'search') {
+      // @ts-ignore
+      apiConf.push({tuple: [`:${key}`, {tuple: [field.scale, field.limit]}]})
+    } else {
+      // @ts-ignore
+      apiConf.push({tuple: [`:search`, [{tuple: [field.account.scale, field.account.limit]}, {tuple: [field.status.scale, field.status.limit]}]]})
+    }
+  })
+  return apiConf
+}
diff --git a/src/entities/settings/RichMediaConfig.ts b/src/entities/settings/RichMediaConfig.ts
new file mode 100644
index 0000000000000000000000000000000000000000..21ec0ccdc73ce8e9e6bfa186efcd0c71a93d8b4c
--- /dev/null
+++ b/src/entities/settings/RichMediaConfig.ts
@@ -0,0 +1,12 @@
+import { normalizeApiConfig } from '../../utils/ConvertConfigToState'
+import { configKeys, arrayParams } from '../../data/Config'
+
+export default class RichMediaConfig {
+  constructor(existConfig?) {
+    normalizeApiConfig(existConfig, this, arrayParams[configKeys.RICH_MEDIA])
+  }
+  enabled: boolean = true
+  ignore_hosts: any = ''
+  ignore_tld: any = ''
+  parsers: Array<string> = ['Pleroma.Web.RichMedia.Parsers.TwitterCard', 'Pleroma.Web.RichMedia.Parsers.OGP', 'Pleroma.Web.RichMedia.Parsers.OEmbed']
+}
diff --git a/src/entities/settings/ScheduledActivityConfig.ts b/src/entities/settings/ScheduledActivityConfig.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1106dc716b9bbf1ce437f3c935207609516600ed
--- /dev/null
+++ b/src/entities/settings/ScheduledActivityConfig.ts
@@ -0,0 +1,10 @@
+import { normalizeApiConfig } from '../../utils/ConvertConfigToState'
+
+export default class ScheduledActivityConfig {
+  constructor(existConfig?) {
+    normalizeApiConfig(existConfig, this)
+  }
+  daily_user_limit:number = 25
+  total_user_limit:number = 300
+  enabled:boolean = true
+}
diff --git a/src/entities/settings/SuggestionsConfig.ts b/src/entities/settings/SuggestionsConfig.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ee9fa6b406094f3c0729cbcb62ba66fbbbe2301f
--- /dev/null
+++ b/src/entities/settings/SuggestionsConfig.ts
@@ -0,0 +1,12 @@
+import { normalizeApiConfig } from '../../utils/ConvertConfigToState'
+
+export default class SuggestionsConfig {
+  constructor(existConfig?) {
+    normalizeApiConfig(existConfig, this)
+  }
+  enabled: boolean = false
+  third_party_engine: string = 'http://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-suggestions-api.cgi?{{host}}+{{user}}'
+  timeout: number = 300000
+  limit: number = 41
+  web: string = 'https://vinayaka.distsn.org'
+}
diff --git a/src/entities/settings/UeberauthConfigs.ts b/src/entities/settings/UeberauthConfigs.ts
new file mode 100644
index 0000000000000000000000000000000000000000..90f95d58832b278e2f349498894c308f80dd52f3
--- /dev/null
+++ b/src/entities/settings/UeberauthConfigs.ts
@@ -0,0 +1,27 @@
+import { normalizeApiConfig } from '../../utils/ConvertConfigToState'
+
+class UeberauthBaseOAuth {
+  constructor( existConfig? ) {
+    normalizeApiConfig(existConfig, this)
+  }
+  client_id:string = ''
+  client_secret: string = ''
+}
+
+export class UeberauthTwitterOAuth {
+  constructor( existConfig? ) {
+    normalizeApiConfig(existConfig, this)
+  }
+  consumer_key: string = ''
+  consumer_secret: string = ''
+}
+
+export class UeberauthFacebookOAuth extends UeberauthBaseOAuth{
+  redirect_uri: string = ''
+}
+
+export class UeberauthGoogleOAuth extends UeberauthBaseOAuth{
+  redirect_uri: string = ''
+}
+
+export class UeberauthMicrosoftOAuth extends UeberauthBaseOAuth{}
diff --git a/src/entities/settings/UploadConfig.ts b/src/entities/settings/UploadConfig.ts
new file mode 100644
index 0000000000000000000000000000000000000000..4a1e43fd83a0402ff8d4fd229717549650f140b9
--- /dev/null
+++ b/src/entities/settings/UploadConfig.ts
@@ -0,0 +1,27 @@
+import { normalizeApiConfig } from '../../utils/ConvertConfigToState'
+
+export class ReverseProxy {
+  redirect_on_failure: boolean = false
+  max_body_length?: number
+  max_read_duration: number = 3000
+  inline_content_types: string = 'true'
+  req_headers: string = ''
+  resp_headers: string = ''
+  http: object = {
+    follow_redirect: true,
+    pool: ':upload'
+  }
+}
+
+export default class UploadConfig {
+  constructor (existConfig?) {
+    normalizeApiConfig(existConfig, this)
+  }
+  uploader: string = 'Pleroma.Uploaders.Local'
+  filters: Array<string> = []
+  text: string = ''
+  link_name: boolean = false
+  base_url: string = ''
+  proxy_remote: boolean = false
+  proxy_opts?: ReverseProxy = new ReverseProxy()
+}
diff --git a/src/entities/settings/UploadersLocalConfig.ts b/src/entities/settings/UploadersLocalConfig.ts
new file mode 100644
index 0000000000000000000000000000000000000000..9da95bd36fa7409f2559cb3c638e1599e1286627
--- /dev/null
+++ b/src/entities/settings/UploadersLocalConfig.ts
@@ -0,0 +1,8 @@
+import { normalizeApiConfig } from '../../utils/ConvertConfigToState'
+
+export default class UploadersLocalConfig {
+  constructor (existConfig) {
+    normalizeApiConfig(existConfig, this)
+  }
+  uploads: string = ''
+}
diff --git a/src/entities/settings/UploadersMDIIConfig.ts b/src/entities/settings/UploadersMDIIConfig.ts
new file mode 100644
index 0000000000000000000000000000000000000000..9965204acba95d5b7bf8f4cf7f72f11a26b44b84
--- /dev/null
+++ b/src/entities/settings/UploadersMDIIConfig.ts
@@ -0,0 +1,9 @@
+import { normalizeApiConfig } from '../../utils/ConvertConfigToState'
+
+export default class UploadersMDIIConfig {
+  constructor (existConfig?) {
+    normalizeApiConfig(existConfig, this)
+  }
+  cgi: string = ''
+  files: string = ''
+}
diff --git a/src/entities/settings/UploadersS3Config.ts b/src/entities/settings/UploadersS3Config.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b246ef60aeb74fb1fbb14fd7b12263cd8519c93a
--- /dev/null
+++ b/src/entities/settings/UploadersS3Config.ts
@@ -0,0 +1,10 @@
+import {normalizeApiConfig} from "../../utils/ConvertConfigToState";
+
+export default class UploadersS3Config {
+  constructor (existConfig) {
+    normalizeApiConfig(existConfig, this)
+  }
+  bucket = null
+  public_endpoint: string = ''
+  truncated_namespace: string = ''
+}
diff --git a/src/entities/settings/UriSchemesConfig.ts b/src/entities/settings/UriSchemesConfig.ts
new file mode 100644
index 0000000000000000000000000000000000000000..abe5afef7735717a7b9ad1ab905e9290692ded7b
--- /dev/null
+++ b/src/entities/settings/UriSchemesConfig.ts
@@ -0,0 +1,9 @@
+import {normalizeApiConfig} from '../../utils/ConvertConfigToState'
+
+export default class UriSchemesConfig {
+  constructor (existConfig?) {
+    normalizeApiConfig(existConfig, this)
+  }
+  valid_schemes: Array<String> = []
+  sendAsMap = true
+}
diff --git a/src/entities/settings/UserConfig.ts b/src/entities/settings/UserConfig.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ff6b4878b40bbadf8a2a9b2e741c7e351c71c8fc
--- /dev/null
+++ b/src/entities/settings/UserConfig.ts
@@ -0,0 +1,8 @@
+import { normalizeApiConfig } from '../../utils/ConvertConfigToState'
+
+export default class UserConfig {
+  constructor(existConfig?) {
+    normalizeApiConfig(existConfig, this)
+  }
+  deny_follow_blocked: boolean = true
+}
diff --git a/src/entities/settings/VapidDetailsConfig.ts b/src/entities/settings/VapidDetailsConfig.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1f2f12c81d4ce9ed39aaf1e299897ccade0092c7
--- /dev/null
+++ b/src/entities/settings/VapidDetailsConfig.ts
@@ -0,0 +1,10 @@
+import { normalizeApiConfig } from '../../utils/ConvertConfigToState'
+
+export default class VapidDetailsConfig {
+  constructor(existConfig?) {
+    normalizeApiConfig(existConfig, this)
+  }
+  subject: string = ''
+  public_key: string = ''
+  private_key: string = ''
+}
diff --git a/src/entities/settings/WebAuthenticatorConfig.ts b/src/entities/settings/WebAuthenticatorConfig.ts
new file mode 100644
index 0000000000000000000000000000000000000000..70aab3422c100f7b89e7d79856b467ff4aa5a6f7
--- /dev/null
+++ b/src/entities/settings/WebAuthenticatorConfig.ts
@@ -0,0 +1,10 @@
+export default class WebAuthenticatorConfig {
+  constructor(existConfig?) {
+    if (existConfig) {
+      this.authenticator = existConfig
+    }
+  }
+  authenticator:string = 'none'
+}
+
+export const normalizeWebAuthenticatorConfig = (config) => config[0].tuple[1] === 'none' ? '' : config[0].tuple[1]
diff --git a/src/entities/settings/WebEndpointConfig.ts b/src/entities/settings/WebEndpointConfig.ts
new file mode 100644
index 0000000000000000000000000000000000000000..4f9808e001105342989fd6b5503b2b3508ce9b56
--- /dev/null
+++ b/src/entities/settings/WebEndpointConfig.ts
@@ -0,0 +1,92 @@
+import { normalizeApiConfig } from '../../utils/ConvertConfigToState'
+import {arrayParams, configKeys} from '../../data/Config'
+import data from '../../services/configs'
+
+class Pubsub {
+  name: string = ''
+  adapter: string = ''
+}
+
+class RenderErrors {
+  accepts: any = ''
+  view: string = ''
+}
+
+class Http {
+  dispatch: any = ''
+  port:  number = 400
+  ip: any = [127, 0, 0, 1]
+  protocol_options: object = {
+    max_request_line_length: 8192,
+    max_header_value_length: 8192
+  }
+}
+
+export default class WebEndpointConfig {
+  constructor(existConfig?) {
+    const httpIndex = existConfig.findIndex(({ tuple }) => tuple[0] === ':http')
+    if (httpIndex !== -1) {
+      const ip = existConfig[httpIndex].tuple[1].find(({ tuple }) => tuple[0] === ':ip')
+      if(ip.tuple && ip) {
+        this.http.ip = ip.tuple[1] && ip.tuple[1].tuple ? ip.tuple[1].tuple.join(';') : ''
+      }
+      const dispatch = existConfig[httpIndex].tuple[1].find(({ tuple }) => tuple[0] === ':dispatch')
+      if (dispatch.tuple && dispatch) {
+        this.http.dispatch = dispatch.tuple[1] ? dispatch.tuple[1][0] : ''
+      }
+      existConfig.splice(httpIndex, 1)
+    }
+    normalizeApiConfig(existConfig, this, arrayParams[configKeys.WEB_ENDPOINT])
+    this.render_errors.accepts = this.render_errors.accepts.join(';')
+  }
+  instrumenters: any = []
+  render_errors: RenderErrors = {
+    view: 'Pleroma.Web.ErrorView',
+    accepts: 'json'
+  }
+  pubsub: Pubsub = {
+    name: 'Pleroma.PubSub',
+    adapter: 'Phoenix.PubSub.PG2'
+  }
+  extra_cookie_attrs: any = ["SameSite=Lax"]
+  debug_errors: boolean = true
+  protocol: string = 'http'
+  signing_salt: string = ''
+  code_reloader: boolean = false
+  check_origin: boolean = false
+  watchers: any = []
+  secure_cookie_flag: boolean = false
+  secret_key_base: string = ''
+  url: object = {
+    host: "localhost",
+    scheme: "https",
+    port: 443
+  }
+  http: Http = {
+    dispatch: '',
+    port: 400,
+    ip: [127, 0, 0, 1],
+    protocol_options: {
+      max_request_line_length: 8192,
+      max_header_value_length: 8192
+    }
+  }
+}
+
+export const normalizeWebEndpointConfig = (config) => {
+  const apiConf = [...config]
+  const render_errors = apiConf.find(({ tuple }) => tuple[0] === ':render_errors')
+  if (render_errors.tuple && render_errors && render_errors.tuple[1]) {
+    const accepts = render_errors.tuple[1].find(({ tuple }) => tuple[0] === ':accepts')
+    accepts.tuple[1] = accepts.tuple[1].split(';')
+  }
+  const http = apiConf.find(({ tuple }) => tuple[0] === ':http')
+  if (http.tuple && http && http.tuple[1]) {
+    const dispatch = http.tuple[1].find(({ tuple }) => tuple[0] === ':dispatch')
+    dispatch.tuple[1] = [dispatch.tuple[1]]
+    const ip = http.tuple[1].find(({ tuple }) => tuple[0] === ':ip')
+    ip.tuple[1] = { tuple: ip.tuple[1].split(';')}
+  }
+  return apiConf
+  // return data.configs.find(({ key }) => key === configKeys.WEB_ENDPOINT).value
+}
diff --git a/src/entities/settings/WebFederationQueueConfig.ts b/src/entities/settings/WebFederationQueueConfig.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1b151361adff78218c0e846a6d88b6881c232140
--- /dev/null
+++ b/src/entities/settings/WebFederationQueueConfig.ts
@@ -0,0 +1,11 @@
+import { normalizeApiConfig } from '../../utils/ConvertConfigToState'
+
+export default class WebFederationQueueConfig {
+  constructor(existConfig?) {
+    normalizeApiConfig(existConfig, this)
+  }
+  enabled: boolean = false
+  max_jobs: number = 0
+  initial_timeout: number = 0
+  max_retries: number = 0
+}
diff --git a/src/entities/settings/WebMetadataConfig.ts b/src/entities/settings/WebMetadataConfig.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1c1d912fe2baad0d36f175616d3ca9434b12ab63
--- /dev/null
+++ b/src/entities/settings/WebMetadataConfig.ts
@@ -0,0 +1,7 @@
+import { normalizeApiConfig } from '../../utils/ConvertConfigToState'
+
+export default class WebMetadataConfig {
+  constructor(existConfig?) {
+    normalizeApiConfig(existConfig, this)
+  }
+}
diff --git a/src/i18n/en.json b/src/i18n/en.json
index 67885732057e6ac4a6ae8004a2b34bcf5b43c743..4ef53d5bcbc5d34dd595c3aa2f867ea1683d4cb8 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -48,23 +48,11 @@
     "gray": "GRAY",
     "dark": "DARK"
   },
-  "charts": {
-    "horizontalBarChart": "Horizontal Bar Chart",
-    "verticalBarChart": "Vertical Bar Chart",
-    "lineChart": "Line Chart",
-    "pieChart": "Pie Chart",
-    "donutChart": "Donut Chart",
-    "bubbleChart": "Bubble Chart"
-  },
   "collapse": {
     "basic": "Basic Collapse",
     "collapseWithBackground": "Collapse with background",
     "collapseWithCustomHeader": "Collapse with custom header"
   },
-  "sliders": {
-    "slider": "Sliders",
-    "range": "Ranges"
-  },
   "dashboard": {
     "dataVisualization": "Data Visualization",
     "success": "SUCCESS",
@@ -76,40 +64,6 @@
     "usersAndMembers": "Users & Members",
     "versions": "Versions"
   },
-  "notificationsPage": {
-    "notifications": {
-      "title": "Notifications",
-      "gray": "Processing",
-      "dark": "New Label",
-      "success": "Paid",
-      "successMessage": "You successfully read this important alert message.",
-      "info": "Info",
-      "infoMessage": "This alert needs your attention, but it's not super important.",
-      "warning": "On Hold",
-      "warningMessage": "Better check yourself, you're not looking too good.",
-      "danger": "Danger",
-      "dangerMessage": "Change a few things up and try submitting again."
-    },
-    "popovers": {
-      "title": "Tooltips & Popovers",
-      "popoverTitleLabel": "Popover Title",
-      "popoverTextLabel": "Popover Text",
-      "popoverIconLabel": "Popover Icon (fontawesome)",
-      "showPopover": "Show Popover",
-      "topTooltip": "top tooltip",
-      "rightTooltip": "rightside tooltip",
-      "leftTooltip": "left",
-      "bottomTooltip": "below"
-    },
-    "toasts": {
-      "title": "Toasts",
-      "textLabel": "Text",
-      "durationLabel": "Duration (milliseconds)",
-      "iconLabel": "Icon (fontawesome)",
-      "fullWidthLabel": "Fullwidth",
-      "launchToast": "Launch toast"
-    }
-  },
   "extra": {
     "tabs": {
       "title": "Tabs",
@@ -182,6 +136,52 @@
       "verticalSimple": "Vertical Simple Wizard"
     }
   },
+  "charts": {
+    "horizontalBarChart": "Horizontal Bar Chart",
+    "verticalBarChart": "Vertical Bar Chart",
+    "lineChart": "Line Chart",
+    "pieChart": "Pie Chart",
+    "donutChart": "Donut Chart",
+    "bubbleChart": "Bubble Chart"
+  },
+  "sliders": {
+    "slider": "Sliders",
+    "range": "Ranges"
+  },
+  "notificationsPage": {
+    "notifications": {
+      "title": "Notifications",
+      "gray": "Processing",
+      "dark": "New Label",
+      "success": "Paid",
+      "successMessage": "You successfully read this important alert message.",
+      "info": "Info",
+      "infoMessage": "This alert needs your attention, but it's not super important.",
+      "warning": "On Hold",
+      "warningMessage": "Better check yourself, you're not looking too good.",
+      "danger": "Danger",
+      "dangerMessage": "Change a few things up and try submitting again."
+    },
+    "popovers": {
+      "title": "Tooltips & Popovers",
+      "popoverTitleLabel": "Popover Title",
+      "popoverTextLabel": "Popover Text",
+      "popoverIconLabel": "Popover Icon (fontawesome)",
+      "showPopover": "Show Popover",
+      "topTooltip": "top tooltip",
+      "rightTooltip": "rightside tooltip",
+      "leftTooltip": "left",
+      "bottomTooltip": "below"
+    },
+    "toasts": {
+      "title": "Toasts",
+      "textLabel": "Text",
+      "durationLabel": "Duration (milliseconds)",
+      "iconLabel": "Icon (fontawesome)",
+      "fullWidthLabel": "Fullwidth",
+      "launchToast": "Launch toast"
+    }
+  },
   "grid": {
     "desktop": "Desktop Grid",
     "fixed": "Fixed Grid",
@@ -206,7 +206,8 @@
   },
   "menu": {
     "users": "Users",
-    "reports": "Reports"
+    "reports": "Reports",
+    "config": "Config Settings"
   },
   "messages": {
     "all": "See all messages",
@@ -350,20 +351,22 @@
       "action2": "Action 2"
     }
   },
-  "login-placeholder": "username@instance",
-  "password-placeholder": "password",
-  "statuses": "Statuses",
-  "following": "Following",
-  "followers": "Followers",
+  "pleroma": {
+    "login-placeholder": "username@instance",
+    "password-placeholder": "password",
+    "statuses": "Statuses",
+    "following": "Following",
+    "followers": "Followers"
+  },
   "no_followers": "No more followers",
   "no_followings": "No more followings",
   "no_followers_yet": "No followers yet",
   "no_followings_yet": "No followings yet",
   "no_statuses": "No more statuses",
   "no_statuses_yet": "No statuses yet",
+  "no_users_found": "No users found",
   "no_reports": "No more reports",
   "no_reports_yet": "No reports yet",
-  "no_users_found": "No users found",
   "load_more": "Load more",
   "admin_menu": {
     "moderation": "Moderation",
@@ -431,5 +434,762 @@
     "delete_status": "Delete status",
     "delete_status_message": "Are you absolutely sure? This action cannot be undone.",
     "add_note_placeholder": "Add note..."
+  },
+  "config_settings": {
+    "tabs": {
+      "Pleroma.Emails.Mailer": "Emails",
+      "Pleroma.Upload": "Upload",
+      ":frontend_configurations": "Frontend configurations",
+      "Pleroma.Captcha": "Captcha",
+      "Pleroma.Web.Endpoint": "Endpoint",
+      "Pleroma.Web.Metadata": "Metadata",
+      ":instance": "Instance",
+      ":database": "Database options",
+      ":gopher": "Gopher",
+      ":auth": "Authentication",
+      ":mrf_simple": "MRF",
+      ":vapid_details": "Web push encryption",
+      ":activitypub": "Activity pub",
+      ":suggestions": "Suggestions",
+      ":uri_schemes": "URI schemes",
+      ":media_proxy": "Media proxy",
+      ":ldap": "LDAP",
+      ":http_security": "HTTP security",
+      ":rate_limit": "Rate limit",
+      ":user": "User",
+      ":rich_media": "Rich media",
+      ":fetch_initial_posts": "Fetch initial posts",
+      ":hackney_pools": "Hackney pools",
+      ":auto_linker": "Auto linker",
+      "Pleroma.ScheduledActivity": "Scheduled activity",
+      ":queues": "Job queue",
+      ":admin_token":  "Admin token",
+      ":esshd": "BBS / SSH access"
+    },
+    "Pleroma": {
+      "Upload_form": {
+        "uploader": "Uploader",
+        "uploader_note": "",
+        "filters": "Filters",
+        "filters_note": "",
+        "args": "List of actions for the mogrify command",
+        "args_note": "",
+        "link_name": "Link name",
+        "link_name_note": "When enabled Pleroma will add a name parameter to the url of the upload, for example https://instance.tld/media/corndog.png?name=corndog.png. This is needed to provide the correct filename in Content-Disposition headers when using filters like Pleroma.Upload.Filter.Dedupe",
+        "base_url": "Base URL",
+        "base_url_note": "",
+        "proxy_remote": "Proxy remote",
+        "proxy_remote_note": "If you're using a remote uploader, Pleroma will proxy media requests instead of redirecting to it.",
+        "redirect_on_failure": "Redirect on failure",
+        "redirect_on_failure_note": "Redirects the client to the real remote URL if there's any HTTP errors. Any error during body processing will not be redirected as the response is chunked.",
+        "text": "Anonymize filename",
+        "text_note": "Text to replace filenames in links. If empty, {random}.extension will be used. You can get the original filename extension by using {extension}, for example custom-file-name.{extension}.\n"
+      },
+      "Uploaders": {
+        "Local_form": {
+          "title": "Pleroma.Uploaders.Local",
+          "uploads": "Uploads",
+          "uploads_note": "Which directory to store the user-uploads in, relative to pleroma’s working directory"
+        },
+        "S3_form": {
+          "title": "Pleroma.Uploaders.S3",
+          "bucket": "S3 bucket name",
+          "bucket_note": "",
+          "public_endpoint": "S3 endpoint that the user finally accesses",
+          "public_endpoint_note": "",
+          "truncated_namespace": "Truncated_namespace",
+          "truncated_namespace_note": "If you use S3 compatible service such as Digital Ocean Spaces or CDN, set folder name or \"\" etc.\n        For example, when using CDN to S3 virtual host format, set \"\".\n        At this time, write CNAME to CDN in public_endpoint."
+        },
+        "MDII_form": {
+          "title": "Pleroma.Uploaders.MDII",
+          "cgi": "CGI",
+          "cgi_note": "",
+          "files": "Files",
+          "files_note": ""
+        }
+      },
+      "Emails.Mailer_form": {
+        "adapters_options": "Adapter's option",
+        "add_adapted_option": "Add adapter option",
+        "option_name": "Name",
+        "option_value": "Value",
+        "enabled": "Enabled",
+        "adapter": "Adapter",
+        "choose_type_of_field": "Choose type of field"
+      },
+      "Captcha_form": {
+        "enabled": "Enabled",
+        "enabled_note": "Whether the captcha should be shown on registration",
+        "method": "Method",
+        "method_note": "The method/service to use for captcha",
+        "seconds_valid": "Seconds valid",
+        "seconds_valid_note": ""
+      },
+      "Captcha.Kocaptcha_form": {
+        "title": "Kocaptcha service",
+        "endpoint": "The kocaptcha endpoint to use",
+        "endpoint_note": ""
+      },
+      "ScheduledActivity_form": {
+        "daily_user_limit": "Daily user limit",
+        "daily_user_limit_note": "The number of scheduled activities a user is allowed to create in a single day (Default: 25)",
+        "total_user_limit": "Total user limit",
+        "total_user_limit_note": "The number of scheduled activities a user is allowed to create in total (Default: 300)",
+        "enabled": "Enabled",
+        "enabled_note": "Whether scheduled activities are sent to the job queue to be executed"
+      },
+      "Web": {
+      "Metadata_form": {
+        "unfurl_nsfw": "Show nsfw attachments in previews",
+        "unfurl_nsfw_note": "",
+        "providers": "Providers",
+        "providers_note": "Pleroma.Web.Metadata.Providers.RelMe - add links from user bio with rel=me into the <header> as <link rel=me>"
+      },
+      "Federator.RetryQueue_form": {
+        "title": "Web.Federator.RetryQueue",
+        "enabled": "Enabled",
+        "enabled_note": "",
+        "max_jobs": "Max jobs",
+        "max_jobs_note": "The maximum amount of parallel federation jobs running at the same time",
+        "initial_timeout": "Initial timeout (seconds)",
+        "initial_timeout_note": "",
+        "max_retries": "The maximum number of times a federation job is retried",
+        "max_retries_note": ""
+      },
+      "Auth.Authenticator_form": {
+        "authenticator": "Authenticator",
+        "authenticator_note": ""
+      },
+      "Endpoint_form": {
+        "instrumenters": "Instrumenters",
+        "instrumenters_note": "",
+        "secure_cookie_flag": "Secure cookie flag",
+        "secure_cookie_flag_note": "",
+        "check_origin": "Check origin",
+        "check_origin_note": "",
+        "protocol": "Protocol",
+        "protocol_note": "",
+        "signing_salt": "Signing salt",
+        "signing_salt_note": "",
+        "secret_key_base": "Secret key base",
+        "secret_key_base_note": "",
+        "debug_errors": "Debug errors",
+        "debug_errors_note": "",
+        "code_reloader": "Code reloader",
+        "code_reloader_note": "",
+        "extra_cookie_attrs": "Extra cookie attributes",
+        "extra_cookie_attrs_note": "",
+        "watchers": "Watchers",
+        "watchers_note": ""
+      }
+    }
+  },
+    ":uri_schemes_form": {
+      "valid_schemes": "Valid schemes",
+      "valid_schemes_note": "List of the scheme part that is considered valid to be an URL"
+    },
+    ":instance_form": {
+      "name": "Name",
+      "name_note": "The instance’s name",
+      "email": "Email",
+      "email_note": "Email used to reach an Administrator/Moderator of the instance",
+      "notify_email": "Notify email",
+      "notify_email_note": "Email used for notifications",
+      "description": "Description",
+      "description_note": "The instance’s description, can be seen in nodeinfo and /api/v1/instance",
+      "limit": "Limit",
+      "limit_note": "Posts character limit (CW/Subject included in the counter)",
+      "remote_limit": "Remote limit",
+      "remote_limit_note": "Hard character limit beyond which remote posts will be dropped.",
+      "upload_limit": "Upload limit",
+      "upload_limit_note": "File size limit of uploads (except for avatar, background, banner)",
+      "avatar_upload_limit": "Avatar upload limit",
+      "avatar_upload_limit_note": "File size limit of user’s profile avatars",
+      "background_upload_limit": "Background upload limit",
+      "background_upload_limit_note": "File size limit of user’s profile backgrounds",
+      "banner_upload_limit": "Banner upload limit",
+      "banner_upload_limit_note": "File size limit of user’s profile banners",
+      "poll_limits": "A map with poll limits for local polls",
+      "account_activation_required": "Account activation required",
+      "account_activation_required_note": "Require users to confirm their emails before signing in",
+      "federating": "Federating",
+      "federating_note": "Enable federation with other instances",
+      "federation_reachability_timeout_days": "Federation reachability timeout days",
+      "federation_reachability_timeout_days_note": "Timeout (in days) of each external federation target being unreachable prior to pausing federating to it.",
+      "federation_incoming_replies_max_depth": "Max. depth of reply-to activities fetching on incoming federation",
+      "federation_incoming_replies_max_depth_note": "Used to prevent out-of-memory situations while fetching very long threads. If set to nil, threads of any depth will be fetched. Lower this value if you experience out-of-memory crashes.",
+      "federation_publisher_modules": "",
+      "federation_publisher_modules_note": "",
+      "dedupe_media": "Dedupe media",
+      "dedupe_media_note": "",
+      "allow_relay": "Allow relay",
+      "allow_relay_note": "Enable Pleroma’s Relay, which makes it possible to follow a whole instance",
+      "rewrite_policy": "Rewrite policy",
+      "rewrite_policy_note": "Message Rewrite Policy, either one or a list",
+      "public": "Public",
+      "public_note": "Makes the client API in authentificated mode-only except for user-profiles. Useful for disabling the Local Timeline and The Whole Known Network.",
+      "quarantined_instances": "Quarantined instances",
+      "quarantined_instances_note": "List of ActivityPub instances where private(DMs, followers-only) activities will not be send. Separate items with ';'",
+      "managed_config": "Managed config",
+      "managed_config_note": "Whenether the config for pleroma-fe is configured in this config or in static/config.json",
+      "static_dir": "Static directory",
+      "static_dir_note": "",
+      "allowed_post_formats": "Allowed post formats",
+      "allowed_post_formats_note": "MIME-type list of formats allowed to be posted (transformed into HTML)",
+      "mrf_transparency": "mrf transparency",
+      "mrf_transparency_note": "Make the content of your Message Rewrite Facility settings public (via nodeinfo)",
+      "mrf_transparency_exclusions": "Exclude specific instance names from MRF transparency.",
+      "mrf_transparency_exclusions_note": "The use of the exclusions feature will be disclosed in nodeinfo as a boolean value. Separate items with ';'",
+      "extended_nickname_format": "Extended nickname format",
+      "extended_nickname_format_note": "Set to true to use extended local nicknames format (allows underscores/dashes). This will break federation with folder software for theses nicknames.",
+      "max_pinned_statuses": "Max pinned status",
+      "max_pinned_statuses_note": "The maximum number of pinned statuses. 0 will disable the feature.",
+      "autofollowed_nicknames": "Autofollowed nicknames",
+      "autofollowed_nicknames_note": "Set to nicknames of (local) users that every new user should automatically follow. Separate items with ';'",
+      "no_attachment_links": "No attachment links",
+      "no_attachment_links_note": "Set to true to disable automatically adding attachment link text to statuses",
+      "welcome_message": "Welcome message",
+      "welcome_message_note": "A message that will be send to a newly registered users as a direct message.",
+      "welcome_user_nickname": "Welcome user nickname",
+      "welcome_user_nickname_note": "The nickname of the local user that sends the welcome message.",
+      "max_report_comment_size": "Max report comment size",
+      "max_report_comment_size_note": "The maximum size of the report comment (Default: 1000)",
+      "safe_dm_mentions": "Safe dm mentions",
+      "safe_dm_mentions_note": " If set to true, only mentions at the beginning of a post will be used to address people in direct messages. This is to prevent accidental mentioning of people when talking about them (e.g. \"@friend hey i really don't like @enemy\")",
+      "healthcheck": "Healthcheck",
+      "healthcheck_note": "If set to true, system data will be shown on /api/pleroma/healthcheck.",
+      "remote_post_retention_days": "Remote post retention days",
+      "remote_post_retention_days_note": "The default amount of days to retain remote posts when pruning the database.",
+      "skip_thread_containment": "Skip thread containment",
+      "limit_to_local_content": "Limit to local content",
+      "limit_to_local_content_note": "Limit unauthenticated users to search for local statutes and users only.",
+      "dynamic_configuration": "Dynamic configuration",
+      "dynamic_configuration_note": "Allow transferring configuration to DB with the subsequent customization from Admin api.",
+      "external_user_synchronization": "External user synchronization",
+      "external_user_synchronization_note": "Enabling following/followers counters synchronization for external users.",
+      "registrations_open": "Registrations open",
+      "registrations_open_note": "Enable registrations for anyone, invitations can be enabled when false.",
+      "invites_enabled": "Invites enabled",
+      "invites_enabled_note": "Enable user invitations for admins (depends on registrations_open: false)."
+    },
+    "poll_limits_form": {
+      "title": "Poll limits",
+      "max_option_chars": "Maximum number of characters per option",
+      "max_option_chars_note": "",
+      "min_expiration": "Minimum expiration time (in seconds)",
+      "min_expiration_note": "",
+      "max_expiration": "Maximum expiration time (in seconds)",
+      "max_expiration_note": "",
+      "max_options": "Maximum number of options",
+      "max_options_note": ""
+    },
+    "pleroma_fe_form" : {
+      "title": "Pleroma FE",
+      "theme": "theme",
+      "theme_note": "Which theme to use",
+      "logo_note": "URL of the logo, defaults to Pleroma’s logo",
+      "logoMask": "Logo mask",
+      "logoMask_note": "Whether to use only the logo's shape as a mask (true) or as a regular image (false)",
+      "logoMargin": "Logo margin",
+      "logoMargin_note": "What margin to use around the logo",
+      "background": "Background",
+      "background_note": "URL of the background, unless viewing a user profile with a background that is set",
+      "redirectUrl": "Redirect URL",
+      "redirectUrl_note": "",
+      "redirectRootNoLogin": "Relative URL which indicates where to redirect when a user isn’t logged in.",
+      "redirectRootNoLogin_note": "",
+      "redirectRootLogin": "Relative URL which indicates where to redirect when a user is logged in.",
+      "redirectRootLogin_note": "",
+      "showInstanceSpecificPanel": "Show instance specific panel",
+      "showInstanceSpecificPanel_note": "Whenether to show the instance’s specific panel.",
+      "subjectLineBehavior": "Subject line behavior",
+      "subjectLineBehavior_note": "Allows changing the default behaviour of subject lines in replies",
+      "scopeOptionsEnabled": "Enable scope options",
+      "scopeOptionsEnabled_note": "Enable setting an notice visibility and subject/CW when posting",
+      "scopeCopy": "Scope copy",
+      "scopeCopy_note": "Copy the scope (private/unlisted/public) in replies to posts by default.",
+      "formattingOptionsEnabled": "Enable formatting options",
+      "formattingOptionsEnabled_note": "Enable setting a formatting different than plain-text (ie. HTML, Markdown) when posting",
+      "collapseMessageWithSubject": "Collapse message with subject",
+      "collapseMessageWithSubject_note": "When a message has a subject(aka Content Warning), collapse it by default",
+      "alwaysShowSubjectInput": "Always show subject input",
+      "alwaysShowSubjectInput_note": "When set to false, auto-hide the subject field when it's empty.",
+      "hidePostStats": "Hide notices statistics",
+      "hidePostStats_note": "",
+      "hideUserStats": "Hide profile statistics",
+      "hideUserStats_note": ""
+    },
+    "masto_fe_form": {
+      "title": "Masto FE",
+      "showInstanceSpecificPanel": "Show instance specific panel",
+      "showInstanceSpecificPanel_note": "Whenether to show the instance’s specific panel."
+    },
+    ":database_form" : {
+      "rum_enabled": "RUM indexing for full text search",
+      "rum_enabled_note": "If RUM indexes should be used"
+    },
+    ":ecto_repos_form": {
+      "ecto_repos": "Ecto repos",
+      "ecto_repos_note": "Separate items with ;"
+    },
+    ":media_proxy_form": {
+      "whitelist": "Whitelist",
+      "whitelist_note": "List of domains to bypass the mediaproxy. Separate items with ';'",
+      "enabled": "Enabled",
+      "enabled_note": "Enables proxying of remote media to the instance’s proxy",
+      "redirect_on_failure": "Redirect on failure",
+      "redirect_on_failure_note": "",
+      "base_url": "Base URL",
+      "base_url_note": "The base URL to access a user-uploaded file. Useful when you want to proxy the media files via another host/CDN fronts."
+    },
+    "proxy_opts_form": {
+      "title": "Proxy options",
+      "redirect_on_failure": "Redirect on failure",
+      "redirect_on_failure_note": "Redirects the client to the real remote URL if there's any HTTP errors. Any error during body processing will not be redirected as the response is chunked.",
+      "max_body_length": "Max body length",
+      "max_body_length_note": "limits the content length to be approximately the specified length. It is validated with the content-length header and also verified when proxying.",
+      "max_read_duration": "Max read duration",
+      "max_read_duration_note": "The total time the connection is allowed to read from the remote upstream.",
+      "inline_content_types": "Inline content types",
+      "inline_content_types_note": "true - Will not alter `content-disposition` (up to the upstream); false - Will add content-disposition: attachment to any request",
+      "req_headers": "Request headers",
+      "resp_headers": "Response headers",
+      "resp_headers_note": "",
+      "req_headers_note": "Additional headers"
+    },
+    "http_form": {
+      "title": "HTTP",
+      "follow_redirect": "Follow redirect",
+      "follow_redirect_note": "",
+      "pool": "Pool",
+      "pool_note": "",
+      "port": "Port",
+      "port_note": "",
+      "ip": "IP",
+      "ip_note": "",
+      "dispatch": "Dispatch",
+      "dispatch_note": "Elixir code snipped"
+    },
+    ":ldap_form": {
+      "title": "Use LDAP for user authentication.  When a user logs in to the Pleroma\ninstance, the name and password will be verified by trying to authenticate\n(bind) to an LDAP server.  If a user exists in the LDAP directory but there\nis no account with the same name yet on the Pleroma instance then a new\nPleroma account will be created with the same name as the LDAP user name.",
+      "enabled": "Enabled",
+      "enabled_note": "Enables LDAP authentication",
+      "host": "LDAP server hostname",
+      "host_note": "",
+      "port": "LDAP port",
+      "port_note": "e.g. 389 or 636",
+      "ssl": "SSL",
+      "ssl_note": "true to use SSL, usually implies the port 636",
+      "sslopts": "Additional SSL options",
+      "sslopts_note": "Saparate items with ;",
+      "tls": "TLS",
+      "tls_note": "true to start TLS, usually implies the port 389",
+      "tlsopts": "Additional TLS options",
+      "tlsopts_note": "Separate items with ';'",
+      "base": "LDAP base",
+      "base_note": "e.g. 'dc=example,dc=com'",
+      "uid": "UID",
+      "uid_note": "LDAP attribute name to authenticate the user, e.g. when 'cn', the filter will be 'cn=username,base'"
+    },
+    ":activitypub_form": {
+      "accept_blocks": "Accept blocks",
+      "accept_blocks_note":"Whether to accept incoming block activities from other instances",
+      "unfollow_blocked": "Unfollow blocked",
+      "unfollow_blocked_note": "Whether blocks result in people getting unfollowed",
+      "outgoing_blocks": "Outgoing blocks",
+      "outgoing_blocks_note": "Whether to federate blocks to other instances",
+      "sign_object_fetches": "Sign object fetches with HTTP signatures",
+      "sign_object_fetches_note": "",
+      "follow_handshake_timeout": "Follow handshake timeout",
+      "follow_handshake_timeout_note": ""
+    },
+    ":user_form": {
+      "deny_follow_blocked": "Deny follow blocked",
+      "deny_follow_blocked_note": "Whether to disallow following an account that has blocked the user in question"
+    },
+    ":http_security_form": {
+      "enabled": "Enabled",
+      "enabled_note": "Whether the managed content security policy is enabled",
+      "sts": "Send Strict-Transport-Security header",
+      "sts_note": "",
+      "sts_max_age": "The maximum age for the Strict-Transport-Security header",
+      "sts_max_age_note": "",
+      "ct_max_age": "The maximum age for the Expect-CT header",
+      "ct_max_age_note": "",
+      "referrer_policy": "Referrer policy",
+      "referrer_policy_note": ""
+    },
+    ":rich_media_form": {
+      "enabled": "Enabled",
+      "enabled_note": "If enabled the instance will parse metadata from attached links to generate link previews",
+      "ignore_hosts": "Ignored hosts",
+      "ignore_hosts_note": "List of hosts which will be ignored by the metadata parser. Separate items with ';'",
+      "ignore_tld": "Ignored top-level domains",
+      "ignore_tld_note": "List TLDs (top-level domains) which will ignore for parse metadata. Separate items with ';'",
+      "parsers": "Parsers",
+      "parsers_note": "",
+      "ttl_setters": "TTL setters",
+      "ttl_setters_note": "Separate items with ';'"
+    },
+    ":fetch_initial_posts_form": {
+      "enabled": "Enabled",
+      "enabled_note": "If enabled, when a new user is federated with, fetch some of their latest posts",
+      "pages": "Pages",
+      "pages_note": "The amount of pages to fetch"
+    },
+    "federation_form": {
+      "title": "For the federation jobs.\nYou may want this pool max_connections to be at least equal to the number of federator jobs + retry queue jobs.",
+      "max_connections": "Maximum of connections",
+      "max_connections_note": "How much connections a pool can hold",
+      "timeout": "Timeout",
+      "timeout_note": "Retention duration for connections"
+    },
+    "media_form": {
+      "title": "For rich media, media proxy",
+      "max_connections": "Maximum of connections",
+      "max_connections_note": "How much connections a pool can hold",
+      "timeout": "Timeout",
+      "timeout_note": "Retention duration for connections"
+    },
+    "upload_form": {
+      "title": "For uploaded media (if using a remote uploader and proxy_remote: true)",
+      "max_connections": "Maximum of connections",
+      "max_connections_note": "How much connections a pool can hold",
+      "timeout": "Timeout",
+      "timeout_note": "Retention duration for connections"
+    },
+    "opts_form": {
+      "scheme": "Scheme",
+      "scheme_note": "Set to true to link urls with schema http://google.com",
+      "class": "Class",
+      "class_note": "Will be added to the generated link. Set false to clear",
+      "rel": "Rel",
+      "rel_note": "Override the rel attribute.Set false to clear,",
+      "new_window": "New window",
+      "new_window_note": "Set to false to remove target='_blank' attribute",
+      "strip_prefix": "Strip the scheme prefix",
+      "strip_prefix_note": "",
+      "extra": "Extra",
+      "extra_note": "false - link urls with rarely used schemes (magnet, ipfs, irc, etc.)",
+      "validate_tld": "Validate TLD",
+      "validate_tld_note": ""
+    },
+    ":oauth2_form": {
+      "title": "OAuth2",
+      "token_expires_in": "Token expires in",
+      "token_expires_in_note": "The lifetime in seconds of the access token",
+      "issue_new_refresh_token": "Issue new refresh token",
+      "issue_new_refresh_token_note": "Keeps old refresh token or generate new refresh token when to obtain an access token",
+      "clean_expired_tokens": "Clean expired tokens",
+      "clean_expired_tokens_note": "Enable a background job to clean expired oauth tokens. Defaults to false.",
+      "clean_expired_tokens_interval": "Clean expired tokens interval",
+      "clean_expired_tokens_interval_note": "Interval to run the job to clean expired tokens. Defaults to 86400000 (24 hours)"
+    },
+    "search_form": {
+      "title": "Search"
+    },
+    "account_form": {
+      "title": "Account",
+      "scale": "Scale",
+      "scale_note": "The time scale in milliseconds",
+      "limit_note": "How many requests to limit in the time scale provided."
+    },
+    "status_form": {
+      "title": "Status",
+      "scale": "Scale",
+      "scale_note": "The time scale in milliseconds",
+      "limit": "Limit",
+      "limit_note": "How many requests to limit in the time scale provided."
+    },
+    "app_account_creation_form": {
+      "title": "App account creation form",
+      "scale": "Scale",
+      "scale_note": "The time scale in milliseconds",
+      "limit": "Limit",
+      "limit_note": "How many requests to limit in the time scale provided."
+    },
+    "relations_actions_form": {
+      "title": "Relations actions",
+      "scale": "Scale",
+      "scale_note": "The time scale in milliseconds",
+      "limit": "Limit",
+      "limit_note": "How many requests to limit in the time scale provided."
+    },
+    "relation_id_action_form": {
+      "title": "Relation is action",
+      "scale": "Scale",
+      "scale_note": "The time scale in milliseconds",
+      "limit": "Limit",
+      "limit_note": "How many requests to limit in the time scale provided."
+    },
+    "statuses_actions_form": {
+      "title": "Statuses actions",
+      "scale": "Scale",
+      "scale_note": "The time scale in milliseconds",
+      "limit": "Limit",
+      "limit_note": "How many requests to limit in the time scale provided."
+    },
+    "status_id_action_form": {
+      "title": "Status id action",
+      "scale": "Scale",
+      "scale_note": "The time scale in milliseconds",
+      "limit": "Limit",
+      "limit_note": "How many requests to limit in the time scale provided."
+    },
+    "password_reset_form": {
+      "title": "Password reset",
+      "scale": "Scale",
+      "scale_note": "The time scale in milliseconds",
+      "limit": "Limit",
+      "limit_note": "How many requests to limit in the time scale provided."
+    },
+    ":chat_form": {
+      "title": "Chat",
+      "enabled": "Enabled",
+      "enabled_note": ""
+    },
+    ":gopher_form": {
+      "enabled": "Enabled",
+      "enabled_note": "Enables the gopher interface",
+      "ip": "IP address",
+      "ip_note": "",
+      "port": "Port",
+      "port_note": "",
+      "dstport": "Dst port",
+      "dstport_note": "Port advertised in urls (optional, defaults to port)"
+    },
+    ":emoji_form": {
+      "title": "Emoji",
+      "shortcode_globs": "Locations of custom emoji files",
+      "shortcode_globs_note": "* can be used as a wildcard",
+      "add_shortcode_glob": "Add one more location",
+      "pack_extensions": "A list of file extensions for emojis",
+      "pack_extensions_note": "Used, when no emoji.txt for a pack is present. Separate items with ';'",
+      "default_manifest": "Location of the JSON-manifest",
+      "default_manifest_note": "This manifest contains information about the emoji-packs you can download. Currently only one manifest can be added (no arrays)",
+      "groups": "Emoji groups",
+      "groups_note": " Emojis are ordered in groups (tags). This is an array of key-value pairs where the key is the groupname and the value the location or array of locations. * can be used as a wildcard"
+    },
+    ":assets_form": {
+      "title": "This section configures assets to be used with various frontends. Currently the only option relates to mascots on the mastodon frontend",
+      "mascots": "Keyword list of mascots",
+      "name": "Name",
+      "mime_type": "Mime type",
+      "url": "URL",
+      "mascots_error": "MUST contain both a url and a mime_type key",
+      "default_mascot": "Default mascot on MastoFE",
+      "add_mascots": "Add mascot"
+    },
+    ":mrf_simple_form": {
+      "title": "MRF Simple",
+      "media_removal": "List of instances to remove medias from",
+      "media_removal_note": "Separate items with ;",
+      "media_nsfw": "List of instances to put medias as NSFW(sensitive) from",
+      "media_nsfw_note": "Separate items with ;",
+      "federated_timeline_removal": "List of instances to remove from Federated (aka The Whole Known Network) Timeline",
+      "federated_timeline_removal_note": "Separate items with ;",
+      "reject": "List of instances to reject any activities from",
+      "reject_note": "Separate items with ;",
+      "accept": "List of instances to accept any activities from",
+      "accept_note": "Separate items with ;",
+      "report_removal": "List of instances to reject reports from",
+      "report_removal_note": "Separate items with ;",
+      "avatar_removal": "List of instances to strip avatars from",
+      "avatar_removal_note": "Separate items with ;",
+      "banner_removal": "List of instances to strip banners from",
+      "banner_removal_note": "Separate items with ;"
+    },
+    ":mrf_mention_form": {
+      "title": "MRF mention",
+      "actors": "Actors",
+      "actors_note": "A list of actors, for which to drop any posts mentioning"
+    },
+    ":mrf_subchain_form": {
+      "title": "MRF subchain",
+      "note": "This policy processes messages through an alternate pipeline when a given message matches certain criteria. All criteria are configured as a map of regular expressions to lists of policy modules",
+      "regular_expression": "Regular expression",
+      "policy_modules": "Policy modules",
+      "add_match_actor": "Add match actor"
+    },
+    ":mrf_rejectnonpublic_form": {
+      "title": "MRF reject non public",
+      "allow_followersonly": "Allow followers only",
+      "allow_followersonly_note": "whether to allow followers-only posts",
+      "allow_direct": "Allow direct",
+      "allow_direct_note": "whether to allow direct messages"
+    },
+    ":mrf_hellthread_form": {
+      "title": "MRF Heallthread",
+      "delist_threshold": "",
+      "delist_threshold_note": "Number of mentioned users after which the message gets delisted (the message can still be seen, but it will not show up in public timelines and mentioned users won't get notifications about it). Set to 0 to disable.",
+      "reject_threshold": "",
+      "reject_threshold_note": "Number of mentioned users after which the messaged gets rejected. Set to 0 to disable."
+    },
+    ":mrf_keyword_form": {
+      "title": "MRF keyword",
+      "reject": "Reject",
+      "reject_note": "A list of patterns which result in message being rejected, each pattern can be a string or a regular expression. Separate items with ;",
+      "federated_timeline_removal": "Federated timeline removal",
+      "federated_timeline_removal_note": "A list of patterns which result in message being removed from federated timelines (a.k.a unlisted), each pattern can be a string or a regular expression. Separate items with ;",
+      "replace": "Replace",
+      "add_replace_item": "Add replace tuple",
+      "pattern": "Pattern",
+      "replacement": "Replacement",
+      "replace_note": "A list of tuples containing {pattern, replacement}, pattern can be a string or a regular expression"
+    },
+    ":mrf_normalize_markup_form": {
+      "title": "MRF mormalize markup",
+      "scrub_policy": "Scrub policy",
+      "scrub_policy_note": ""
+    },
+    ":mrf_user_allowlist_form": {
+      "title": "MRF user allowlist",
+      "note": "The keys in this section are the domain names that the policy should apply to. Each key should be assigned a list of users that should be allowed through by their ActivityPub ID",
+      "domain": "Domain",
+      "list_of_users": "List of users",
+      "add_domain": "Add domain"
+    },
+    ":mrf_vocabulary_form": {
+      "title": "MRF Vocabulary",
+      "accept": "Accept",
+      "accept_note": "A list of ActivityStreams terms to accept.  If empty, all supported messages are accepted. Separate items with ;",
+      "reject": "Reject",
+      "reject_note": "A list of ActivityStreams terms to reject.  If empty, no messages are rejected. Separate items with ;"
+    },
+    ":suggestions_form": {
+      "enabled": "Enabled",
+      "enabled_note": "",
+      "third_party_engine": "Third-party engine",
+      "third_party_engine_note": "",
+      "timeout": "Timeout",
+      "timeout_note": "",
+      "limit": "Limit",
+      "limit_note": "",
+      "web": "Web",
+      "web_note": ""
+    },
+    ":vapid_details_form": {
+      "subject": "Subject",
+      "subject_note": "A mailto link for the administrative contact. It’s best if this email is not a personal email address, but rather a group email so that if a person leaves an organization, is unavailable for an extended period, or otherwise can’t respond, someone else on the list can",
+      "public_key": "VAPID public key",
+      "public_key_note": "",
+      "private_key": "VAPID private key",
+      "private_key_note": ""
+    },
+    "protocol_options_form": {
+      "title": "Protocol options",
+      "max_request_line_length": "Max request line length",
+      "max_request_line_length_note": "",
+      "max_header_value_length": "Max header value length",
+      "max_header_value_length_note": ""
+    },
+    "render_errors_form": {
+      "title": "Render errors",
+      "view": "View",
+      "view_note": "",
+      "accepts": "Accepts",
+      "accepts_note": "Separate items with ;"
+    },
+    "pubsub_form": {
+      "title": "Pubsub",
+      "name": "Name",
+      "name_note": "",
+      "adapter": "Adapter",
+      "adapter_note": ""
+    },
+    "url_form": {
+      "title": "URL",
+      "host": "Host",
+      "host_note": "",
+      "scheme": "Scheme",
+      "scheme_note": "",
+      "port": "Port",
+      "port_note": ""
+    },
+    ":queues_form": {
+      "federator_outgoing": "Outgoing federation",
+      "federator_outgoing_note": "",
+      "federator_incoming": "Incoming federation",
+      "federator_incoming_note": "",
+      "mailer": "Email sender",
+      "mailer_note": "",
+      "transmogrifier": "Transmogrifier",
+      "transmogrifier_note": "",
+      "web_push": "Web push notifications",
+      "web_push_note": "",
+      "scheduled_activities": "Scheduled activities",
+      "scheduled_activities_note": ""
+    },
+    ":auth_form": {
+      "auth_template": "authentication form template",
+      "auth_template_note": "By default it's show.html which corresponds to lib/pleroma/web/templates/o_auth/o_auth/show.html.eex",
+      "oauth_consumer_template": "OAuth consumer mode authentication form template",
+      "oauth_consumer_template_note": "By default it's consumer.html which corresponds to lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex",
+      "oauth_consumer_strategies": "OAuth consumer strategies",
+      "oauth_consumer_strategies_note": "By default it's set by OAUTH_CONSUMER_STRATEGIES environment variable. Each entry in this space-delimited string should be of format <strategy> or <strategy>:<dependency> (e.g. twitter or keycloak:ueberauth_keycloak_strategy in case dependency is named differently than ueberauth_<strategy>)"
+    },
+    ":admin_token_form": {
+      "token": "Admin token",
+      "token_note": "Allows to set a token that can be used to authenticate with the admin api without using an actual user by giving it as the 'admin_token' parameter"
+    },
+    "Ueberauth.Strategy": {
+      "Twitter.OAuth_form": {
+        "title": "Ueberauth.Strategy.Twitter",
+        "consumer_key": "Consumer key",
+        "consumer_key_note": "",
+        "consumer_secret": "Consumer secret",
+        "consumer_secret_note": ""
+      },
+      "Facebook.OAuth_form": {
+        "title": "Ueberauth.Strategy.Facebook",
+        "client_id": "Client id",
+        "client_id_note": "",
+        "client_secret": "Client secret",
+        "client_secret_note": "",
+        "redirect_uri": "Redirect URI",
+        "redirect_uri_note": ""
+      },
+      "Google.OAuth_form": {
+        "title": "Ueberauth.Strategy.Google",
+        "client_id": "Client id",
+        "client_id_note": "",
+        "client_secret": "Client secret",
+        "client_secret_note": "",
+        "redirect_uri": "Redirect URI",
+        "redirect_uri_note": ""
+      },
+      "Microsoft.OAuth_form": {
+        "title": "Ueberauth.Strategy.Microsoft",
+        "client_id": "Client id",
+        "client_id_note": "",
+        "client_secret": "Client secret",
+        "client_secret_note": ""
+      }
+    },
+    ":markup_form": {
+      "title": "Markup",
+      "allow_inline_images": "Allow inline images",
+      "allow_inline_images_note": "",
+      "allow_headings": "Allow headings",
+      "allow_headings_note": "",
+      "allow_tables": "Allow tables",
+      "allow_tables_note": "",
+      "allow_fonts": "Allow fonts",
+      "allow_fonts_note": "",
+      "scrub_policy":"Scrub policy",
+      "scrub_policy_note": "Separate items with ;"
+    },
+    ":esshd_form": {
+      "enabled": "Enabled",
+      "enabled_note": "",
+      "priv_dir": "Priv dir",
+      "priv_dir_note": "",
+      "handler": "Habdler",
+      "handler_note": "",
+      "port": "Port",
+      "port_note": "",
+      "password_authenticator": "Password authenticator",
+      "password_authenticator_note": ""
+    }
   }
 }
diff --git a/src/router/router.js b/src/router/router.js
index 7ca10a71a76c0ec68aa047346b3464ce21cebc47..99592d06f6f502f05bbf84db3908276ea005248f 100644
--- a/src/router/router.js
+++ b/src/router/router.js
@@ -38,6 +38,11 @@ export default new Router({
           path: 'report/:id',
           name: 'reportDetails',
           component: () => import('../components/pages/reports/ReportPage.vue')
+        },
+        {
+          path: 'config',
+          name: 'config',
+          component: () => import('../components/pages/configSettings/ConfigSettingsPage.vue')
         }
       ]
     },
diff --git a/src/services/ConfigService.ts b/src/services/ConfigService.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d6447c9ba5abbf0c3f7c63e960dbabfc3eff07ac
--- /dev/null
+++ b/src/services/ConfigService.ts
@@ -0,0 +1,22 @@
+import {reportsList} from '../data/ReportsList.mock'
+import {report, unresolvedReport} from '../data/Report.mock'
+import executeApiRequest from './executeApiRequest'
+import urlBuilder, {Url} from './urlBuilder'
+
+export class ConfigService {
+  static listConfigSettings () {
+    return executeApiRequest('get', urlBuilder(Url.configSettings, {}), {})
+  }
+
+  static updateConfigSettings (configs) {
+    // console.log(configs)
+    // return new Promise(res => {
+    //   setTimeout(() => res({}), 1000)
+    // })
+    return executeApiRequest('post', urlBuilder(Url.configSettings, {}), {data: configs})
+  }
+
+  static setConfigToDB () {
+    return executeApiRequest('get', urlBuilder(Url.setConfigToDB, {}), {})
+  }
+}
diff --git a/src/services/StaticRecourcesService.ts b/src/services/StaticRecourcesService.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1837eb3aced1ab14c735254a6a77bf898a6d66df
--- /dev/null
+++ b/src/services/StaticRecourcesService.ts
@@ -0,0 +1,8 @@
+import executeApiRequest from './executeApiRequest'
+import urlBuilder, {Url} from './urlBuilder'
+
+export class StaticRecourcesService {
+  static getThemesList () {
+    return executeApiRequest('get', urlBuilder(Url.getThemesList, {}), {})
+  }
+}
diff --git a/src/services/executeApiRequest.js b/src/services/executeApiRequest.js
index d6be52a7a372e283d2a9c69be5fca9b5813fd7b2..77c100281bee404e7f6b557353072378ba0e6309 100644
--- a/src/services/executeApiRequest.js
+++ b/src/services/executeApiRequest.js
@@ -1,5 +1,6 @@
 import { axiosInstance } from './axiosInstance'
 import Router from '../router/router'
+import t from 'typy'
 
 export default function (method, url, data, options) {
   return axiosInstance({
@@ -9,7 +10,7 @@ export default function (method, url, data, options) {
   })
     .then((res) => options && options.returnFullRes ? res : res.data)
     .catch(err => {
-      if (err.response.status === 403) {
+      if (t(err, 'response.status').safeObject === 403) {
         Router.push({ name: 'login' })
       } else {
         throw err
diff --git a/src/services/urlBuilder.ts b/src/services/urlBuilder.ts
index 133c62e63306a7909f5e17a230ed03cbae61bde3..cef2dd0956ba7b7fa59e6ec31d3e1584cc6d6034 100644
--- a/src/services/urlBuilder.ts
+++ b/src/services/urlBuilder.ts
@@ -29,6 +29,9 @@ export enum Url {
   changeReportState = 'changeReportState',
   respondReport = 'respondReport',
   changeReportedStatus = 'changeReportedStatus',
+  configSettings = 'configSettings',
+  setConfigToDB = 'setConfigToDB',
+  getThemesList = 'getThemesList',
 }
 
 export enum UserData {
@@ -49,22 +52,25 @@ interface UrlBuilderOptions {
 }
 
 const urls = {
-  [Url.getUsers]: () => 'pleroma/admin/users',
-  [Url.getUser]: (options: UrlBuilderOptions) => `v1/accounts/${options.id}`,
-  [Url.getSimplifiedUser]: (options: UrlBuilderOptions) => `pleroma/admin/users/${options.id}`,
-  [Url.getUserData]: (options: UrlBuilderOptions) => `v1/accounts/${options.id}/${options.dataType}`,
-  [Url.toggleTag]: () => 'pleroma/admin/users/tag/',
-  [Url.toggleUserActivation]: (options: UrlBuilderOptions) => `pleroma/admin/users/${options.id}/activation_status`,
-  [Url.togglePermissionGroup]: (options: UrlBuilderOptions) => `pleroma/admin/users/${options.id}/permission_group/${options.permissionGroup}`,
-  [Url.deleteUser]: (options: UrlBuilderOptions) => `pleroma/admin/user`,
-  [Url.getReports]: (options: UrlBuilderOptions) => `pleroma/admin/reports`,
-  [Url.getReport]: (options: UrlBuilderOptions) => `pleroma/admin/reports/${options.id}`,
-  [Url.changeReportState]: (options: UrlBuilderOptions) => `pleroma/admin/reports/${options.id}`,
-  [Url.respondReport]: (options: UrlBuilderOptions) => `pleroma/admin/reports/${options.id}/respond`,
-  [Url.changeReportedStatus]: (options: UrlBuilderOptions) => `pleroma/admin/statuses/${options.id}`
+  [Url.getUsers]: () => 'api/pleroma/admin/users',
+  [Url.getSimplifiedUser]: (options: UrlBuilderOptions) => `api/pleroma/admin/users/${options.id}`,
+  [Url.getUser]: (options: UrlBuilderOptions) => `api/v1/accounts/${options.id}`,
+  [Url.getUserData]: (options: UrlBuilderOptions) => `api/v1/accounts/${options.id}/${options.dataType}`,
+  [Url.toggleTag]: () => 'api/pleroma/admin/users/tag/',
+  [Url.toggleUserActivation]: (options: UrlBuilderOptions) => `api/pleroma/admin/users/${options.id}/activation_status`,
+  [Url.togglePermissionGroup]: (options: UrlBuilderOptions) => `api/pleroma/admin/users/${options.id}/permission_group/${options.permissionGroup}`,
+  [Url.deleteUser]: (options: UrlBuilderOptions) => `api/pleroma/admin/user`,
+  [Url.getReports]: (options: UrlBuilderOptions) => `api/pleroma/admin/reports`,
+  [Url.getReport]: (options: UrlBuilderOptions) => `api/pleroma/admin/reports/${options.id}`,
+  [Url.changeReportState]: (options: UrlBuilderOptions) => `api/pleroma/admin/reports/${options.id}`,
+  [Url.respondReport]: (options: UrlBuilderOptions) => `api/pleroma/admin/reports/${options.id}/respond`,
+  [Url.changeReportedStatus]: (options: UrlBuilderOptions) => `api/pleroma/admin/statuses/${options.id}`,
+  [Url.configSettings]: (options: UrlBuilderOptions) => `api/pleroma/admin/config`,
+  [Url.setConfigToDB]: (options: UrlBuilderOptions) => `api/pleroma/admin/config_to_db`,
+  [Url.getThemesList]: (options: UrlBuilderOptions) => 'static/styles.json',
 }
 
 export default (action: Url, options: UrlBuilderOptions):string => {
   const code = getAll()
-  return `https://${code.instance}/api/${urls[action](options)}`
+  return `https://${code.instance}/${urls[action](options)}`
 }
diff --git a/src/utils/ConvertConfigToApiRequest.js b/src/utils/ConvertConfigToApiRequest.js
new file mode 100644
index 0000000000000000000000000000000000000000..604393ad159ebc171e5a1b6666085d2decbe7348
--- /dev/null
+++ b/src/utils/ConvertConfigToApiRequest.js
@@ -0,0 +1,70 @@
+import { forIn, isEqual } from 'lodash'
+import { arrayParams, configKeys, normalizerMapper, getConfigGroup } from '../data/Config'
+import { normalizeRateLimitConfig } from '../entities/settings/RateLimitConfig'
+import JobQueueConfig from '../entities/settings/JobQueueConfig'
+
+export default (configs) => {
+  const settings = []
+  forIn(configs, (val, key) => {
+    let newVal = { ...val }
+    if (arrayParams[key]) {
+      newVal = normalizeConfigValue(newVal, key)
+    }
+    if (normalizerMapper[key] && normalizerMapper[key].normalizeBeforeGeneralFunc) {
+      newVal = normalizerMapper[key].normalizer(newVal)
+    }
+    newVal = key !== configKeys.RATE_LIMIT ? getConfigValue(newVal) : normalizeRateLimitConfig(newVal)
+    if (normalizerMapper[key] && !normalizerMapper[key].normalizeBeforeGeneralFunc) {
+      newVal = normalizerMapper[key].normalizer(newVal)
+    }
+    if (checkConfigIsNeedsToBePushed(key, newVal)) {
+      settings.push({
+        group: getConfigGroup(key),
+        key,
+        value: newVal
+      })
+    }
+  })
+  return { configs: settings }
+}
+
+const checkConfigIsNeedsToBePushed = (key, configVal) => {
+  return (key !== configKeys.MRF_USER_ALLOWLIST ||
+    (key === configKeys.MRF_USER_ALLOWLIST && !!configVal.length)) &&
+    (key !== configKeys.JOB_QUEUE ||
+    (key === configKeys.JOB_QUEUE && !isEqual(getConfigValue(new JobQueueConfig()), configVal))) &&
+    (key !== configKeys.ADMIN_TOKEN ||
+    (key === configKeys.ADMIN_TOKEN && !!configVal.length))
+}
+
+const normalizeConfigValue = (config, key) => {
+  arrayParams[key].forEach(param => {
+    config[param] = config[param] ? config[param].split(';') : []
+  })
+  return config
+}
+
+const getConfigValue = (config) => {
+  const newConfig = []
+  createTupledObject(newConfig, config)
+  function createTupledObject (resultConfig, nestedObj) {
+    forIn(nestedObj, (val, key) => {
+      if (val && typeof val === 'object' && !Array.isArray(val)) {
+        if (val.sendAsMap) {
+          delete val.sendAsMap
+          const resultVal = {}
+          forIn(val, (innerVal, innerKey) => {
+            resultVal[`:${innerKey}`] = innerVal
+          })
+          resultConfig.push({ tuple: [`:${key}`, resultVal] })
+        } else {
+          resultConfig.push({ tuple: [`:${key}`, createTupledObject([], val)] })
+        }
+      } else {
+        resultConfig.push({ tuple: [`:${key}`, val] })
+      }
+    })
+    return resultConfig
+  }
+  return newConfig
+}
diff --git a/src/utils/ConvertConfigToState.ts b/src/utils/ConvertConfigToState.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1b41e63053c0bb0fb0d000560c442d2b47a9afda
--- /dev/null
+++ b/src/utils/ConvertConfigToState.ts
@@ -0,0 +1,61 @@
+import t from 'typy'
+import { forIn } from 'lodash'
+import { configKeysTabs } from '../data/Config'
+
+export default (configs) => {
+  const configObj = {}
+  configKeysTabs.forEach(({ key, constructor }) => {
+    const apiConfig = configs.find(item => key === item.key)
+    // @ts-ignore
+    configObj[key] = new constructor(t(apiConfig, 'value').safeObject)
+  })
+  return configObj
+}
+
+export const normalizeApiConfig = function(existConfig, classObject, arrayParams?) {
+  if (existConfig) {
+    const newConfig = parseObj(existConfig, classObject)
+    if (arrayParams && arrayParams.length) {
+      convertArrayParamsToState(newConfig, arrayParams)
+    }
+    return newConfig
+  }
+  function parseObj(config, resultObject) {
+    config.forEach(({tuple}) => {
+      const key = tuple[0]
+      const val = tuple[1]
+      if (typeof val === 'object') {
+        if (Array.isArray(val)) {
+          const a = val.find(item => typeof item === 'object' && item.tuple)
+          if (a) {
+            delete resultObject[key]
+            resultObject[key.substring(1)] = parseObj(val, resultObject[key.substring(1)])
+          } else {
+            resultObject[key.substring(1)] = val
+          }
+        } else {
+          forIn(val, (value, innerKey) => {
+            delete val[innerKey]
+            val[innerKey.substring(1)] = value
+          })
+          if (resultObject[key.substring(1)] && resultObject[key.substring(1)].sendAsMap) {
+            val.sendAsMap = true
+          }
+          resultObject[key.substring(1)] = val
+        }
+      } else {
+        resultObject[key.substring(1)] = val
+      }
+    })
+    return resultObject
+  }
+
+}
+export const convertArrayParamsToState = (config, arrayParams) => {
+  arrayParams.forEach(param => {
+    config[param] = (config[param] && Array.isArray(config[param]))
+      ? config[param].join(';')
+      : config[param]
+  })
+  return config
+}
diff --git a/src/utils/GetFieldList.ts b/src/utils/GetFieldList.ts
new file mode 100644
index 0000000000000000000000000000000000000000..291c5c2f1a110d027e571347b77db6939f76636b
--- /dev/null
+++ b/src/utils/GetFieldList.ts
@@ -0,0 +1,87 @@
+import { forIn, get } from 'lodash'
+
+export const selectOptions = {
+  adapter: [
+    'Swoosh.Adapters.Local',
+    'Swoosh.Adapters.SMTP',
+    'Swoosh.Adapters.Sendgrid',
+    'Swoosh.Adapters.Sendmail',
+    'Swoosh.Adapters.Mandrill',
+    'Swoosh.Adapters.Mailgun',
+    'Swoosh.Adapters.Mailjet',
+    'Swoosh.Adapters.Postmark',
+    'Swoosh.Adapters.SparkPost',
+    'Swoosh.Adapters.AmazonSES',
+    'Swoosh.Adapters.Dyn',
+    'Swoosh.Adapters.SocketLabs',
+    'Swoosh.Adapters.Gmail',
+  ],
+  rewrite_policy: [
+    'Pleroma.Web.ActivityPub.MRF.NoOpPolicy',
+    'Pleroma.Web.ActivityPub.MRF.DropPolicy',
+    'Pleroma.Web.ActivityPub.MRF.SimplePolicy',
+    'Pleroma.Web.ActivityPub.MRF.TagPolicy',
+    'Pleroma.Web.ActivityPub.MRF.SubchainPolicy',
+    'Pleroma.Web.ActivityPub.MRF.RejectNonPublic',
+    'Pleroma.Web.ActivityPub.MRF.EnsureRePrepended',
+    'Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicy',
+    'Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy',
+    'Pleroma.Web.ActivityPub.MRF.VocabularyPolicy'
+  ],
+  allowed_post_formats: ['text/plain', 'text/html', 'text/markdown', 'text/bbcode'],
+  limit_to_local_content: [':unauthenticated', ':all', 'false'],
+  federation_publisher_modules: ['Pleroma.Web.ActivityPub.Publisher', 'Pleroma.Web.Websub', 'Pleroma.Web.Salmon'],
+  method: ['Pleroma.Captcha.Kocaptcha'],
+  theme: [],
+  subject_line_behavior: ['email', 'masto', 'noop'],
+  uploader: ['Pleroma.Uploaders.Local', 'Pleroma.Uploaders.S3'],
+  filters: ['Pleroma.Upload.Filter.Mogrify', 'Pleroma.Upload.Filter.Dedupe', 'Pleroma.Upload.Filter.AnonymizeFilename'],
+  args: ['strip', 'auto-orient', `{'impode': '1'}`],
+  inline_content_types: ['true', 'false', 'a list of whitelisted content types'],
+  valid_schemes: ['https', 'http', 'dat', 'dweb', 'gopher', 'ipfs', 'ipns', 'irc', 'ircs', 'magnet', 'mailto', 'mumble', 'ssb', 'xmpp'],
+  referrer_policy: ['same-origin', 'no-referrer'],
+  parsers: ['Pleroma.Web.RichMedia.Parsers.TwitterCard', 'Pleroma.Web.RichMedia.Parsers.OGP', 'Pleroma.Web.RichMedia.Parsers.OEmbed'],
+  providers: ['Pleroma.Web.Metadata.Providers.OpenGraph', 'Pleroma.Web.Metadata.Providers.TwitterCard', 'Pleroma.Web.Metadata.Providers.RelMe'],
+  authenticator: [ 'none', 'Pleroma.Web.Auth.PleromaAuthenticator', 'Pleroma.Web.Auth.LDAPAuthenticator']
+}
+
+export default (formData) => {
+  const list: Array<object> = []
+  forIn(formData, (val, key) => {
+    //TODO: type
+    if (key === 'sendAsMap') {
+      return
+    }
+    const field = getFieldComponent(val, key)
+    if (field.component) {
+      list.push(field)
+    }
+  })
+  return list
+}
+
+export const getFieldComponent = (val, key?) => {
+  const field: any= {
+    component: '',
+    model: key,
+  }
+  if (key && selectOptions[key]) {
+    field.component = 'va-select'
+    if (Array.isArray(val)){
+      field.multiple = true
+    }
+  } else if (typeof val === 'string'){
+    field.component = 'va-input'
+    if (val.length > 140) {
+      field.isTextarea = true
+    }
+  } else if (typeof val === 'number') {
+    field.component = 'va-input'
+    field.isNumber = true
+  } else if (typeof val === 'boolean') {
+    field.component = 'va-checkbox'
+  } else if (typeof val === 'object' && val){
+    field.component = 'parent'
+  }
+  return field
+}
diff --git a/src/services/utils.js b/src/utils/utils.js
similarity index 100%
rename from src/services/utils.js
rename to src/utils/utils.js
diff --git a/src/vuestic-theme/vuestic-components/va-button/VaButton.vue b/src/vuestic-theme/vuestic-components/va-button/VaButton.vue
index 1fa884f84cf23cb0e7997b0ddf3faa6d0be4a96b..b73cf91415faff4c9bdfb389af5e420e026544a5 100644
--- a/src/vuestic-theme/vuestic-components/va-button/VaButton.vue
+++ b/src/vuestic-theme/vuestic-components/va-button/VaButton.vue
@@ -26,7 +26,7 @@
         v-if="icon"
         fixed-width
         class="va-button__content__icon va-button__content__icon-left"
-        :icon="icon"
+        :name="icon"
       />
       <div
         v-if="hasTitleData"
@@ -37,7 +37,7 @@
         v-if="iconRight"
         fixed-width
         class="va-button__content__icon va-button__content__icon-right"
-        :icon="iconRight"
+        :name="iconRight"
       />
     </div>
   </component>
diff --git a/src/vuestic-theme/vuestic-components/va-checkbox/KeyboardOnlyFocusMixin.js b/src/vuestic-theme/vuestic-components/va-checkbox/KeyboardOnlyFocusMixin.js
new file mode 100644
index 0000000000000000000000000000000000000000..4d6e9bb9b48f259481f3d91fd4617a371d20c7ba
--- /dev/null
+++ b/src/vuestic-theme/vuestic-components/va-checkbox/KeyboardOnlyFocusMixin.js
@@ -0,0 +1,16 @@
+export const KeyboardOnlyFocusMixin = {
+  data () {
+    return {
+      isKeyboardFocused: false,
+      hasMouseDown: false,
+    }
+  },
+  methods: {
+    onFocus (e) {
+      if (this.hasMouseDown) {
+        return
+      }
+      this.isKeyboardFocused = true
+    },
+  },
+}
diff --git a/src/vuestic-theme/vuestic-components/va-checkbox/VaCheckbox.demo.vue b/src/vuestic-theme/vuestic-components/va-checkbox/VaCheckbox.demo.vue
index 48e8de5253910d68406fb86092bab89bc6d315c0..8f866c525fcda5af9b0a897b52b31d4c1a1645fc 100644
--- a/src/vuestic-theme/vuestic-components/va-checkbox/VaCheckbox.demo.vue
+++ b/src/vuestic-theme/vuestic-components/va-checkbox/VaCheckbox.demo.vue
@@ -1,33 +1,104 @@
 <template>
-  <div class="demo-container">
-    <div class="demo-container__item">
-      <vuestic-checkbox v-model="value">
-        <div slot="label">
-         Selected
-        </div>
-      </vuestic-checkbox>
-      <vuestic-checkbox v-model="value" label="Readonly" readonly/>
-      <vuestic-checkbox v-model="value" label="Disabled" disabled/>
-      <vuestic-checkbox v-model="value" error label="Error" isError/>
-      <vuestic-checkbox v-model="value" errorMessages="errorMessages" label="Error-message"/>
-      <vuestic-checkbox v-model="value" :errorMessages="errorMessages" :errorCount="2" label="Error-message"/>
-      <vuestic-checkbox v-model="value" error disabled label="Error + disabled"/>
-    </div>
-  </div>
+  <VbDemo>
+    <VbCard title="Default">
+      <va-checkbox v-model="value" label="Selected"/>
+    </VbCard>
+    <VbCard title="Long label">
+      <va-checkbox
+        style="width: 200px"
+        v-model="value"
+        label="Long long long long long long long long long long long long long long long label"
+      />
+    </VbCard>
+    <VbCard title="Readonly">
+      <va-checkbox v-model="value" label="Readonly" readonly/>
+    </VbCard>
+    <VbCard title="Disabled">
+      <va-checkbox v-model="value" label="Disabled" disabled/>
+    </VbCard>
+    <VbCard title="Disabled to normal comparison">
+      <va-checkbox :value="false" label="Disabled and false" disabled/>
+      <va-checkbox :value="false" label="false"/>
+      <va-checkbox :value="true" label="Disabled and true" disabled/>
+      <va-checkbox :value="true" label="true"/>
+    </VbCard>
+    <VbCard title="Indeterminate">
+      <va-checkbox v-model="value" label="Indeterminate" indeterminate/>
+    </VbCard>
+
+    <VbCard title="Error">
+      <va-checkbox v-model="value" label="Error" error/>
+    </VbCard>
+    <VbCard title="String error message">
+      <va-checkbox
+        v-model="value"
+        label="Error messages"
+        :errorMessages="stringErrorMessage"
+      />
+    </VbCard>
+    <VbCard title="Array error messages">
+      <va-checkbox
+        v-model="value"
+        :errorMessages="errorMessages"
+        label="Multiple error messages"
+      />
+    </VbCard>
+    <VbCard title="Array error messages with maxed limit">
+      <va-checkbox
+        style="width: 200px"
+        v-model="value"
+        :errorMessages="errorMessages"
+        :errorCount="3"
+        label="Label"
+      />
+    </VbCard>
+    <VbCard title="Errors + disabled">
+      <va-checkbox
+        v-model="value"
+        error
+        disabled
+        label="Error + disabled"
+      />
+    </VbCard>
+    <VbCard title="No label">
+      <va-checkbox v-model="value"/>
+    </VbCard>
+    <VbCard title="Accepts id">
+      <va-checkbox
+        :value="true"
+        id="checkbox-id"
+      />
+    </VbCard>
+    <VbCard title="Accepts name">
+      <va-checkbox
+        :value="true"
+        name="checkbox-name"
+      />
+    </VbCard>
+    <VbCard title="Array as model">
+      {{selection}}
+      <va-checkbox v-model="selection" array-value='one' label="one"/>
+      <va-checkbox v-model="selection" array-value='two' label="two"/>
+      <va-checkbox v-model="selection" array-value='three' label="three"/>
+      <va-checkbox v-model="selection" array-value='four' label="four"/>
+    </VbCard>
+  </VbDemo>
 </template>
 
 <script>
-import VuesticCheckbox from './VaCheckbox'
+import VaCheckbox from './VaCheckbox'
 
 export default {
   components: {
-    VuesticCheckbox
+    VaCheckbox,
   },
   data () {
     return {
       value: true,
-      errorMessages: ['error message 1', 'error message 2']
+      selection: [],
+      stringErrorMessage: 'String error message',
+      errorMessages: ['Error message', 'Another error message', 'Long long long long long long long long long long long long long long error message'],
     }
-  }
+  },
 }
 </script>
diff --git a/src/vuestic-theme/vuestic-components/va-checkbox/VaCheckbox.spec.js b/src/vuestic-theme/vuestic-components/va-checkbox/VaCheckbox.spec.js
index 8205417976fa31c384d2a2117e02cba7e599d748..4a31263c7aeaaa10d3d6eae480ef100d7740b232 100644
--- a/src/vuestic-theme/vuestic-components/va-checkbox/VaCheckbox.spec.js
+++ b/src/vuestic-theme/vuestic-components/va-checkbox/VaCheckbox.spec.js
@@ -1,16 +1,20 @@
+import Vue from 'vue'
 import { shallowMount } from '@vue/test-utils'
 import VaCheckbox from './VaCheckbox'
 
+import { ColorThemePlugin } from '../../../services/ColorThemePlugin'
+Vue.use(ColorThemePlugin)
+
 describe('VaCheckbox', () => {
   it('default', () => {
     const wrapper = shallowMount(VaCheckbox, {
-      propsData: { value: false }
+      propsData: { value: false },
     })
     expect(wrapper.html()).toMatchSnapshot()
   })
   it('true value', () => {
     const wrapper = shallowMount(VaCheckbox, {
-      propsData: { value: true }
+      propsData: { value: true },
     })
     expect(wrapper.html()).toMatchSnapshot()
   })
diff --git a/src/vuestic-theme/vuestic-components/va-checkbox/VaCheckbox.vue b/src/vuestic-theme/vuestic-components/va-checkbox/VaCheckbox.vue
index 030d041965cab70da4a3a8c7e55445ba2f54bfec..2694559b2535b4f8185d172d99c39f1820423029 100644
--- a/src/vuestic-theme/vuestic-components/va-checkbox/VaCheckbox.vue
+++ b/src/vuestic-theme/vuestic-components/va-checkbox/VaCheckbox.vue
@@ -6,12 +6,12 @@
     <div
       class="va-checkbox__input-container"
       @click="toggleSelection()"
-      @mousedown="onMouseDown"
-      @mouseup="onMouseUp"
+      @mousedown="hasMouseDown = true"
+      @mouseup="hasMouseDown = false"
     >
       <div
         class="va-checkbox__square"
-        :class="{'active': value}"
+        :class="{'active': isChecked}"
       >
         <input
           :id="id"
@@ -21,8 +21,9 @@
           class="va-checkbox__input"
           @keypress.prevent="toggleSelection()"
           :disabled="disabled"
+          :indeterminate="indeterminate"
         />
-        <va-icon icon="ion ion-md-checkmark va-checkbox__icon-selected"/>
+        <va-icon :name="computedIcon"/>
       </div>
       <div class="va-checkbox__label-text">
         <slot name="label">
@@ -30,41 +31,49 @@
         </slot>
       </div>
     </div>
-    <div class="va-checkbox__error-message-container" v-if="showError">
-      <div
-        class="va-checkbox__error-message"
-        v-for="(error, index) in computedErrorMessages"
-        :key="index"
-      >
-        {{ error }}
-      </div>
-    </div>
+    <va-message-list
+      class="va-checkbox__error-message-container"
+      :value="errorMessages"
+      color="danger"
+      :limit="errorCount"
+    />
   </div>
 </template>
 
 <script>
 import VaIcon from '../va-icon/VaIcon'
+import VaMessageList from '../va-input/VaMessageList'
+import { KeyboardOnlyFocusMixin } from './KeyboardOnlyFocusMixin'
 
 export default {
   name: 'va-checkbox',
-  components: { VaIcon },
+  components: { VaMessageList, VaIcon },
+  mixins: [KeyboardOnlyFocusMixin],
   props: {
+    id: String,
     label: String,
+    name: String,
     value: {
-      type: Boolean,
+      type: [Boolean, Array],
       required: true,
-    },
-    id: {
-      type: String,
-    },
-    disabled: {
-      type: Boolean,
       default: false,
     },
-    readonly: {
-      type: Boolean,
-      default: false,
+    arrayValue: String,
+    indeterminate: Boolean,
+
+    disabled: Boolean,
+    readonly: Boolean,
+
+    checkedIcon: {
+      type: [String, Array],
+      default: 'ion ion-md-checkmark',
     },
+    indeterminateIcon: {
+      type: [String, Array],
+      default: 'ion ion-md-remove',
+    },
+
+    error: Boolean,
     errorMessages: {
       type: [String, Array],
       default: () => [],
@@ -73,40 +82,29 @@ export default {
       type: Number,
       default: 1,
     },
-    name: String,
-    error: {
-      type: Boolean,
-      default: false,
-    },
-  },
-  data () {
-    return {
-      isKeyboardFocused: false,
-      hasMouseDown: false,
-    }
   },
   computed: {
     computedClass () {
       return {
-        'va-checkbox--selected': this.value,
+        'va-checkbox--selected': this.isChecked,
         'va-checkbox--readonly': this.readonly,
         'va-checkbox--disabled': this.disabled,
+        'va-checkbox--indeterminate': this.indeterminate,
         'va-checkbox--error': this.showError,
         'va-checkbox--on-keyboard-focus': this.isKeyboardFocused,
       }
     },
-    computedErrorMessages () {
-      const isArray = Array.isArray(this.errorMessages)
-      const errorMessages = isArray ? this.errorMessages : [this.errorMessages]
-      return errorMessages.slice(0, this.errorCount)
+    computedIcon () {
+      return [
+        'va-checkbox__icon-selected',
+        this.indeterminate ? this.indeterminateIcon : this.checkedIcon,
+      ]
+    },
+    isChecked () {
+      return this.modelIsArray ? this.value.includes(this.arrayValue) : this.value
     },
-    valueProxy: {
-      set (value) {
-        this.$emit('input', value)
-      },
-      get () {
-        return this.value
-      },
+    modelIsArray () {
+      return Array.isArray(this.value)
     },
     showError () {
       // We make error active, if the error-message is not empty and checkbox is not disabled
@@ -119,20 +117,6 @@ export default {
     },
   },
   methods: {
-    onFocus (e) {
-      if (this.hasMouseDown) {
-        return
-      }
-      this.isKeyboardFocused = true
-    },
-    onMouseDown (e) {
-      this.hasMouseDown = true
-      this.$emit('mousedown', e)
-    },
-    onMouseUp (e) {
-      this.hasMouseDown = false
-      this.$emit('mouseup', e)
-    },
     toggleSelection () {
       if (this.readonly) {
         return
@@ -140,120 +124,129 @@ export default {
       if (this.disabled) {
         return
       }
-      this.valueProxy = !this.valueProxy
+      if (this.modelIsArray) {
+        if (this.value.includes(this.arrayValue)) {
+          this.$emit('input', this.value.filter(option => option !== this.arrayValue))
+        } else {
+          this.$emit('input', this.value.concat(this.arrayValue))
+        }
+        return
+      }
+
+      this.$emit('input', !this.value)
     },
   },
 }
 </script>
 
 <style lang="scss">
-  @import "../../vuestic-sass/resources/resources";
+@import "../../vuestic-sass/resources/resources";
 
-  .va-checkbox {
-    margin-bottom: $checkbox-between-items-margin;
-    display: flex;
-    flex-direction: column;
+.va-checkbox {
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
 
-    &__input-container {
-      align-items: center;
-      display: flex;
-      cursor: pointer;
+  &__input-container {
+    align-items: center;
+    display: flex;
+    cursor: pointer;
 
-      @at-root {
-        .va-checkbox--disabled  & {
-          @include va-disabled();
-        }
+    @at-root {
+      .va-checkbox--disabled & {
+        @include va-disabled();
+      }
 
-        .va-checkbox--readonly & {
-          cursor: initial;
-        }
+      .va-checkbox--readonly & {
+        cursor: initial;
+      }
 
-        .va-checkbox--disabled & {
-          cursor: default;
-        }
+      .va-checkbox--disabled & {
+        cursor: default;
       }
     }
+  }
 
-    #{&}__square {
-      @include flex-center();
-      width: 2rem;
-      height: 2rem;
-      position: relative;
-      flex: 0 0 2rem;
-      @at-root {
-        .va-checkbox--on-keyboard-focus#{&} {
-          background-color: $light-gray;
-          transition: all, 0.6s, ease-in;
-          border-radius: 5rem;
-        }
+  #{&}__square {
+    @include flex-center();
+    width: 2rem;
+    height: 2rem;
+    position: relative;
+    flex: 0 0 2rem;
+    @at-root {
+      .va-checkbox--on-keyboard-focus#{&} {
+        background-color: $light-gray;
+        transition: all, 0.6s, ease-in;
+        border-radius: 5rem;
       }
     }
+  }
 
-    #{&}__input {
-      height: 1.375rem;
-      width: 1.375rem;
-      cursor: inherit;
-      color: $white;
-      background-color: $white;
-      border: solid 0.125rem $gray-light;
-      border-radius: 0.25rem;
+  #{&}__input {
+    height: 1.375rem;
+    width: 1.375rem;
+    cursor: inherit;
+    color: $white;
+    background-color: $white;
+    border: solid 0.125rem $gray-light;
+    border-radius: 0.25rem;
+
+    &:focus {
+      outline: none;
+    }
 
-      &:focus {
-        outline: none;
+    @at-root {
+      .va-checkbox--selected#{&} {
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        height: 1.4rem;
+        width: 1.4rem;
+        color: $white;
+        background-color: $vue-green;
+        border: 0;
       }
 
-      @at-root {
-        .va-checkbox--selected#{&} {
-          display: flex;
-          justify-content: center;
-          align-items: center;
-          height: 1.4rem;
-          width: 1.4rem;
-          color: $white;
-          background-color: $vue-green;
-          border: 0;
-        }
-
-        .va-checkbox--error#{&} {
-          border-color: $theme-red;
-        }
+      .va-checkbox--error#{&} {
+        border-color: $theme-red;
       }
     }
+  }
 
-    #{&}__label-text {
-      display: inline-block;
-      position: relative;
-      margin-left: 0.25rem;
-      @at-root {
-        .va-checkbox--error#{&} {
-          color: $theme-red;
-        }
+  #{&}__label-text {
+    display: inline-block;
+    position: relative;
+    margin-left: 0.25rem;
+    @at-root {
+      .va-checkbox--error#{&} {
+        color: $theme-red;
       }
     }
+  }
 
-    &__error-message {
-      vertical-align: middle;
-      color: $theme-red;
-      font-size: $font-size-mini;
-    }
+  &__error-message {
+    vertical-align: middle;
+    color: $theme-red;
+    font-size: $font-size-mini;
+  }
 
-    &__icon-selected {
-      pointer-events: none;
-      position: absolute;
-      color: $white;
-    }
+  &__icon-selected {
+    pointer-events: none;
+    position: absolute;
+    color: $white;
+  }
 
-    &__error-message-container {
-      flex: 0 0 100%;
-      margin-left: 0.3rem; // To fit with checkbox.
-    }
+  &__error-message-container {
+    flex: 0 0 100%;
+    margin-left: 0.3rem; // To fit with checkbox.
+  }
 
-    &__label-container {
-      margin-left: 2rem;
-    }
+  &__label-container {
+    margin-left: 2rem;
+  }
 
-    &__content {
-      flex-direction: row;
-    }
+  &__content {
+    flex-direction: row;
   }
+}
 </style>
diff --git a/src/vuestic-theme/vuestic-components/va-checkbox/__snapshots__/VaCheckbox.spec.js.snap b/src/vuestic-theme/vuestic-components/va-checkbox/__snapshots__/VaCheckbox.spec.js.snap
index 19aeecfdc85a248dd960da24a420861be2d3c21b..60b8777d31ba2d70f9b3c0e62b0b397e028941da 100644
--- a/src/vuestic-theme/vuestic-components/va-checkbox/__snapshots__/VaCheckbox.spec.js.snap
+++ b/src/vuestic-theme/vuestic-components/va-checkbox/__snapshots__/VaCheckbox.spec.js.snap
@@ -1,25 +1,29 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
 exports[`VaCheckbox default 1`] = `
-<div class="vuestic-checkbox">
-  <div class="vuestic-checkbox__square"><input readonly="readonly" class="vuestic-checkbox__input">
-    <va-icon-stub icon="ion ion-md-checkmark vuestic-checkbox__icon-selected"></va-icon-stub>
-  </div>
-  <div class="vuestic-checkbox__label-text">
+<div class="va-checkbox">
+  <div class="va-checkbox__input-container">
+    <div class="va-checkbox__square"><input readonly="readonly" class="va-checkbox__input">
+      <va-icon-stub name="va-checkbox__icon-selected,ion ion-md-checkmark"></va-icon-stub>
+    </div>
+    <div class="va-checkbox__label-text">
 
+    </div>
   </div>
-  <!---->
+  <va-message-list-stub color="danger" value="" limit="1" class="va-checkbox__error-message-container"></va-message-list-stub>
 </div>
 `;
 
 exports[`VaCheckbox true value 1`] = `
-<div class="vuestic-checkbox vuestic-checkbox--selected">
-  <div class="vuestic-checkbox__square active"><input readonly="readonly" class="vuestic-checkbox__input">
-    <va-icon-stub icon="ion ion-md-checkmark vuestic-checkbox__icon-selected"></va-icon-stub>
-  </div>
-  <div class="vuestic-checkbox__label-text">
+<div class="va-checkbox va-checkbox--selected">
+  <div class="va-checkbox__input-container">
+    <div class="va-checkbox__square active"><input readonly="readonly" class="va-checkbox__input">
+      <va-icon-stub name="va-checkbox__icon-selected,ion ion-md-checkmark"></va-icon-stub>
+    </div>
+    <div class="va-checkbox__label-text">
 
+    </div>
   </div>
-  <!---->
+  <va-message-list-stub color="danger" value="" limit="1" class="va-checkbox__error-message-container"></va-message-list-stub>
 </div>
 `;
diff --git a/src/vuestic-theme/vuestic-components/va-checkbox/va-checkbox-docs.md b/src/vuestic-theme/vuestic-components/va-checkbox/va-checkbox-docs.md
new file mode 100644
index 0000000000000000000000000000000000000000..d559fc1f974f0e9dc303dd62adad70cd58e268b2
--- /dev/null
+++ b/src/vuestic-theme/vuestic-components/va-checkbox/va-checkbox-docs.md
@@ -0,0 +1,37 @@
+# Checkbox
+
+Сheckbox supports `disabled` and `checked` attributes
+
+```html
+<va-checkbox
+  v-model="value"
+  label="Selected"
+/>
+<va-checkbox
+  v-model="value"
+  :errorMessages="errorMessages"
+  :errorCount="3"
+  label="With errors"
+/>
+<va-checkbox
+  v-model="array"
+  array-value="one"
+/>
+```
+
+**Props**
+* `id` - String
+* `name` - String
+* `label` - String - label to the right of checkbox
+* `value` - Boolean | Array - main value
+* `arrayValue` - Any
+* `indeterminate` - Boolean - indeterminate state. Note that `value` should be `true` for indeterminate icon to be displayed.
+* `disabled` - Boolean
+* `readonly` - Boolean
+* `checkedIcon` - String | Array (default: 'ion ion-md-checkmark')
+* `indeterminateIcon` - String | Array (default: 'ion ion-md-remove')
+* `errorMessages` - Number - list of error messages for current input field
+* `errorCount` - Number (default: 1) - shows a number of errors to display, given an array of error messages is passed
+* `error` - Boolean - define whether the field is error or not
+
+[See demo](http://vuestic.epicmax.co/#/admin/forms/form-elements)
diff --git a/src/vuestic-theme/vuestic-components/vuestic-color-picker/ColorDot.demo.vue b/src/vuestic-theme/vuestic-components/va-color-picker/ColorDot.demo.vue
similarity index 100%
rename from src/vuestic-theme/vuestic-components/vuestic-color-picker/ColorDot.demo.vue
rename to src/vuestic-theme/vuestic-components/va-color-picker/ColorDot.demo.vue
diff --git a/src/vuestic-theme/vuestic-components/vuestic-color-picker/ColorDot.vue b/src/vuestic-theme/vuestic-components/va-color-picker/ColorDot.vue
similarity index 100%
rename from src/vuestic-theme/vuestic-components/vuestic-color-picker/ColorDot.vue
rename to src/vuestic-theme/vuestic-components/va-color-picker/ColorDot.vue
diff --git a/src/vuestic-theme/vuestic-components/va-color-picker/VaAdvancedColorPicker.demo.vue b/src/vuestic-theme/vuestic-components/va-color-picker/VaAdvancedColorPicker.demo.vue
new file mode 100644
index 0000000000000000000000000000000000000000..f4cb60df470db449763e887e83ea6ed0502d42f1
--- /dev/null
+++ b/src/vuestic-theme/vuestic-components/va-color-picker/VaAdvancedColorPicker.demo.vue
@@ -0,0 +1,26 @@
+<template>
+  <div class="demo-container">
+    <div class="demo-container__item">
+      <va-advanced-color-picker v-model="value"/>
+      {{ value }}
+    </div>
+    <div class="demo-container__item">
+      <va-advanced-color-picker v-model="value"/>
+    </div>
+  </div>
+</template>
+
+<script>
+import VaAdvancedColorPicker from './VaAdvancedColorPicker'
+
+export default {
+  components: {
+    VaAdvancedColorPicker,
+  },
+  data () {
+    return {
+      value: '#AAA',
+    }
+  },
+}
+</script>
diff --git a/src/vuestic-theme/vuestic-components/va-color-picker/VaAdvancedColorPicker.vue b/src/vuestic-theme/vuestic-components/va-color-picker/VaAdvancedColorPicker.vue
new file mode 100644
index 0000000000000000000000000000000000000000..5a15ccb0c6422e8bb49e6fc19099ed8825c5898d
--- /dev/null
+++ b/src/vuestic-theme/vuestic-components/va-color-picker/VaAdvancedColorPicker.vue
@@ -0,0 +1,45 @@
+<template>
+  <ChromePicker v-model="valueProxy" class="va-advanced-color-picker"/>
+</template>
+
+<script>
+import { Chrome } from 'vue-color'
+
+export default {
+  name: 'va-advanced-color-picker',
+  components: {
+    ChromePicker: Chrome,
+  },
+  props: {
+    value: {
+      default: '',
+    },
+  },
+  computed: {
+    valueProxy: {
+      get () {
+        return this.value
+      },
+      set (value) {
+        this.$emit('input', value.hex)
+      },
+    },
+  },
+}
+</script>
+
+<style lang="scss">
+.va-advanced-color-picker {
+  .vc-chrome-alpha-wrap {
+    display: none;
+  }
+
+  .vc-chrome-hue-wrap {
+    margin-top: 10px;
+  }
+
+  .vc-chrome-toggle-btn {
+    display: none;
+  }
+}
+</style>
diff --git a/src/vuestic-theme/vuestic-components/va-color-picker/VaColorInput.demo.vue b/src/vuestic-theme/vuestic-components/va-color-picker/VaColorInput.demo.vue
new file mode 100644
index 0000000000000000000000000000000000000000..993ceda99e3f63f4f22df6e3d11bc024fdd4cca1
--- /dev/null
+++ b/src/vuestic-theme/vuestic-components/va-color-picker/VaColorInput.demo.vue
@@ -0,0 +1,33 @@
+<template>
+  <div class="demo-container">
+    <div class="demo-container__item">
+      <va-color-input v-model="value"/>
+    </div>
+    <div class="demo-container__item">
+      <p>Selected</p>
+      <va-color-input v-model="value" selected/>
+    </div>
+    <div class="demo-container__item">
+      <p>Disabled</p>
+      <va-color-input v-model="value" disabled/>
+    </div>
+    <div class="demo-container__item">
+      <img src="https://i.imgur.com/UjiMAZj.png" alt="">
+    </div>
+  </div>
+</template>
+
+<script>
+import VaColorInput from './VaColorInput'
+
+export default {
+  components: {
+    VaColorInput,
+  },
+  data () {
+    return {
+      value: '#aaaaaa',
+    }
+  },
+}
+</script>
diff --git a/src/vuestic-theme/vuestic-components/va-color-picker/VaColorInput.vue b/src/vuestic-theme/vuestic-components/va-color-picker/VaColorInput.vue
new file mode 100644
index 0000000000000000000000000000000000000000..fdf885890d118e04fb8e1173c4b72177e9e8304c
--- /dev/null
+++ b/src/vuestic-theme/vuestic-components/va-color-picker/VaColorInput.vue
@@ -0,0 +1,87 @@
+<template>
+  <div class="va-color-input">
+    <color-dot
+      class="va-color-input__dot flex-center"
+      :selected="selected"
+      :color="value"
+      @click="onClick"
+    />
+    <div class="form-group">
+      <div class="input-group">
+        <input
+          class="va-color-input__input"
+          :disabled="disabled"
+          v-model="valueProxy"
+          :class="{'va-color-input__input__pointer': disabled}"
+          placeholder="input color"
+        >
+        <va-icon name="bar" :style="'width: ' + 9 + 'ch'"/>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import VaAdvancedColorPicker from './VaAdvancedColorPicker'
+import ColorDot from './ColorDot'
+
+export default {
+  name: 'va-color-input',
+  components: {
+    ColorDot,
+    VaAdvancedColorPicker,
+  },
+  props: {
+    value: {
+      default: '',
+    },
+    disabled: {
+      type: Boolean,
+      default: false,
+    },
+    selected: {
+      type: Boolean,
+      default: false,
+    },
+  },
+  computed: {
+    valueProxy: {
+      get () {
+        return this.value
+      },
+      set (value) {
+        this.$emit('input', value)
+      },
+    },
+  },
+  methods: {
+    onClick () {
+      this.$emit('click')
+    },
+  },
+}
+</script>
+
+<style lang="scss" scoped>
+.va-color-input {
+  display: flex;
+
+  .form-group {
+    margin-bottom: 0;
+  }
+
+  &__dot {
+    margin-top: 7px;
+    margin-right: 8px;
+  }
+
+  &__input {
+    width: 9ch;
+
+    &__pointer {
+      cursor: pointer;
+    }
+  }
+}
+
+</style>
diff --git a/src/vuestic-theme/vuestic-components/va-color-picker/VaColorPickerInput.demo.vue b/src/vuestic-theme/vuestic-components/va-color-picker/VaColorPickerInput.demo.vue
new file mode 100644
index 0000000000000000000000000000000000000000..b7d0eb79271a3249cd9ebfe947ff507c524d751c
--- /dev/null
+++ b/src/vuestic-theme/vuestic-components/va-color-picker/VaColorPickerInput.demo.vue
@@ -0,0 +1,64 @@
+<template>
+  <VbDemo>
+    <VbCard title="slider mode">
+      <va-color-picker-input
+        v-model="value"
+        mode="slider"
+      >
+        <va-color-square :value="value"/>
+      </va-color-picker-input>
+      {{ value }}
+    </VbCard>
+
+    <VbCard title="advanced mode">
+      <va-color-picker-input
+        v-model="value"
+        mode="advanced"
+      >
+        <va-color-input v-model="value"/>
+      </va-color-picker-input>
+    </VbCard>
+
+    <VbCard title="palette mode">
+      <va-color-picker-input
+        v-model="value"
+        mode="palette"
+        :palette="palette"
+      />
+    </VbCard>
+
+    <VbCard title="palette mode with slot">
+      <va-color-picker-input
+        v-model="value"
+        mode="palette"
+        :palette="palette"
+      >
+        <color-dot :color="value"/>
+      </va-color-picker-input>
+      {{ value }}
+    </VbCard>
+  </VbDemo>
+</template>
+
+<script>
+import VaColorPickerInput from './VaColorPickerInput'
+import ColorDot from './ColorDot'
+import VaColorSquare from './VaColorSquare'
+import VaColorInput from './VaColorInput'
+import { colorArray } from './VuesticTheme'
+
+export default {
+  components: {
+    VaColorPickerInput,
+    ColorDot,
+    VaColorSquare,
+    VaColorInput,
+  },
+  data () {
+    return {
+      value: '#9b6caa',
+      palette: colorArray,
+    }
+  },
+}
+</script>
diff --git a/src/vuestic-theme/vuestic-components/va-color-picker/VaColorPickerInput.vue b/src/vuestic-theme/vuestic-components/va-color-picker/VaColorPickerInput.vue
new file mode 100644
index 0000000000000000000000000000000000000000..3e3452a1acddd766d8a49d5319547930d9dd934b
--- /dev/null
+++ b/src/vuestic-theme/vuestic-components/va-color-picker/VaColorPickerInput.vue
@@ -0,0 +1,111 @@
+<template>
+  <div class="va-color-picker-input">
+    <div v-if="validator(this.mode)">
+      <va-dropdown-popper fixed>
+        <div slot="anchor" class="va-color-picker-input__slot">
+          <slot>
+            <va-color-input
+              v-model="valueProxy"
+              mode="palette"
+              :disabled="isInputDisabled"
+              :selected="selected"
+            />
+          </slot>
+        </div>
+        <div class="va-color-picker-input__dropdown">
+          <va-advanced-color-picker
+            v-if="this.mode === 'advanced'"
+            v-model="valueProxy"
+          />
+          <va-simple-palette-picker
+            v-if="this.mode === 'palette'"
+            v-model="valueProxy"
+            :palette="palette"
+          />
+          <va-slider-color-picker
+            v-if="this.mode === 'slider'"
+            v-model="valueProxy"
+          />
+        </div>
+      </va-dropdown-popper>
+    </div>
+    <div v-else>
+      <slot>
+        <va-color-input
+          v-model="valueProxy"
+          mode="palette"
+          :disabled="isInputDisabled"
+        />
+      </slot>
+    </div>
+  </div>
+</template>
+
+<script>
+import VaAdvancedColorPicker from './VaAdvancedColorPicker'
+import VaSimplePalettePicker from './VaSimplePalettePicker'
+import VaSliderColorPicker from './VaSliderColorPicker'
+import VaColorSquare from './VaColorSquare'
+import VaColorInput from './VaColorInput'
+import VaDropdownPopper from '../va-dropdown/VaDropdown'
+
+export default {
+  name: 'va-color-picker-input',
+  components: {
+    VaDropdownPopper,
+    VaColorSquare,
+    VaSimplePalettePicker,
+    VaAdvancedColorPicker,
+    VaSliderColorPicker,
+    VaColorInput,
+  },
+  props: {
+    mode: {
+      type: String,
+    },
+    palette: {
+      type: Array,
+    },
+    value: {
+      default: '',
+    },
+    selected: {
+      type: Boolean,
+      default: false,
+    },
+  },
+  computed: {
+    valueProxy: {
+      get () {
+        return this.value
+      },
+      set (value) {
+        this.$emit('input', value)
+      },
+    },
+    isInputDisabled () {
+      return !!(this.mode === 'palette' && this.palette)
+    },
+  },
+  methods: {
+    validator (value) {
+      return ['palette', 'slider', 'advanced'].includes(value)
+    },
+  },
+}
+</script>
+
+<style lang="scss">
+@import "../../vuestic-sass/resources/resources";
+
+.va-color-picker-input {
+  &__dropdown {
+    background: $white;
+    box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
+  }
+
+  &__slot {
+    cursor: pointer
+  }
+}
+</style>
diff --git a/src/vuestic-theme/vuestic-components/va-color-picker/VaColorSquare.vue b/src/vuestic-theme/vuestic-components/va-color-picker/VaColorSquare.vue
new file mode 100644
index 0000000000000000000000000000000000000000..812a069bb0d3ff3a3b777e143795cc03f6e0b2dd
--- /dev/null
+++ b/src/vuestic-theme/vuestic-components/va-color-picker/VaColorSquare.vue
@@ -0,0 +1,27 @@
+<template>
+  <div
+    class="va-color-square"
+    :style="{'background-color': value}"
+  />
+</template>
+
+<script>
+export default {
+  name: 'va-color-square',
+  props: {
+    value: {
+      required: true,
+    },
+  },
+}
+</script>
+
+<style lang='scss'>
+@import "../../vuestic-sass/resources/resources";
+
+.va-color-square {
+  height: 48px;
+  width: 48px;
+  border: 1px solid $gray-light;
+}
+</style>
diff --git a/src/vuestic-theme/vuestic-components/va-color-picker/VaPaletteCustom.demo.vue b/src/vuestic-theme/vuestic-components/va-color-picker/VaPaletteCustom.demo.vue
new file mode 100644
index 0000000000000000000000000000000000000000..04edbbb3059b60172eae6990cfc41e578fe0751a
--- /dev/null
+++ b/src/vuestic-theme/vuestic-components/va-color-picker/VaPaletteCustom.demo.vue
@@ -0,0 +1,32 @@
+<template>
+  <div class="demo-container">
+    <div class="demo-container__item">
+      <va-palette-custom :palette="palette" v-model="color"/>
+    </div>
+    <div class="demo-container__item">
+      <va-palette-custom :palette="palette" v-model="color"/>
+    </div>
+  </div>
+</template>
+
+<script>
+import { colorArray } from './VuesticTheme'
+
+import VaPaletteCustom from './VaPaletteCustom'
+
+export default {
+  components: {
+    VaPaletteCustom,
+  },
+  data () {
+    return {
+      palette: colorArray,
+      color: '#aaaaaa',
+    }
+  },
+}
+</script>
+
+<style lang="scss">
+
+</style>
diff --git a/src/vuestic-theme/vuestic-components/va-color-picker/VaPaletteCustom.vue b/src/vuestic-theme/vuestic-components/va-color-picker/VaPaletteCustom.vue
new file mode 100644
index 0000000000000000000000000000000000000000..17e57ff6d424c5f65f7d1000b8c5fe4699f6feaf
--- /dev/null
+++ b/src/vuestic-theme/vuestic-components/va-color-picker/VaPaletteCustom.vue
@@ -0,0 +1,67 @@
+<template>
+  <div class="va-palette-custom">
+    <va-simple-palette-picker
+      class="va-palette-custom__palette mr-2"
+      :palette="palette"
+      v-model="valueProxy"
+    />
+    <va-color-picker-input
+      class="va-palette-custom__input"
+      mode="advanced"
+      v-model="valueProxy"
+    >
+      <va-color-input
+        :selected="dotIsSelected"
+        v-model="valueProxy"
+      />
+    </va-color-picker-input>
+  </div>
+</template>
+
+<script>
+
+import VaColorPickerInput from './VaColorPickerInput'
+import VaSimplePalettePicker from './VaSimplePalettePicker'
+import VaColorInput from './VaColorInput'
+
+export default {
+  name: 'va-palette-custom',
+  components: {
+    VaColorInput,
+    VaColorPickerInput,
+    VaSimplePalettePicker,
+  },
+  props: {
+    value: {
+      type: String,
+      default: '',
+    },
+    palette: {
+      type: Array,
+    },
+  },
+  computed: {
+    valueProxy: {
+      get () {
+        return this.value
+      },
+      set (value) {
+        this.$emit('input', value)
+      },
+    },
+    dotIsSelected () {
+      return this.palette.includes(this.value)
+    },
+  },
+}
+</script>
+
+<style lang="scss">
+.va-palette-custom {
+  display: flex;
+
+  &__input {
+    float: right;
+  }
+}
+</style>
diff --git a/src/vuestic-theme/vuestic-components/va-color-picker/VaSimplePalettePicker.demo.vue b/src/vuestic-theme/vuestic-components/va-color-picker/VaSimplePalettePicker.demo.vue
new file mode 100644
index 0000000000000000000000000000000000000000..64e65d02fe4fa0ab5395e41dca01059a4cf8111f
--- /dev/null
+++ b/src/vuestic-theme/vuestic-components/va-color-picker/VaSimplePalettePicker.demo.vue
@@ -0,0 +1,34 @@
+<template>
+  <div class="demo-container">
+    <div class="demo-container__item">
+      <va-simple-palette-picker
+        v-model="value"
+        :palette="palette"
+      />
+      <va-simple-palette-picker
+        v-model="value"
+        :palette="palette"
+      />
+      {{ value }}
+    </div>
+  </div>
+</template>
+
+<script>
+import VaSimplePalettePicker from './VaSimplePalettePicker'
+import { colorArray } from './VuesticTheme'
+import VaPaletteCustom from './VaPaletteCustom'
+
+export default {
+  components: {
+    VaSimplePalettePicker,
+    VaPaletteCustom,
+  },
+  data () {
+    return {
+      value: '#AAA',
+      palette: colorArray,
+    }
+  },
+}
+</script>
diff --git a/src/vuestic-theme/vuestic-components/va-color-picker/VaSimplePalettePicker.vue b/src/vuestic-theme/vuestic-components/va-color-picker/VaSimplePalettePicker.vue
new file mode 100644
index 0000000000000000000000000000000000000000..09db5a5f0d3d5b8ec603f36466f09d1249b60a7c
--- /dev/null
+++ b/src/vuestic-theme/vuestic-components/va-color-picker/VaSimplePalettePicker.vue
@@ -0,0 +1,61 @@
+<template>
+  <div class="va-simple-palette-picker">
+    <ul class="va-simple-palette-picker__colors">
+      <color-dot
+        v-for="(color, index) in palette" :key="index"
+        :color="color"
+        @click.native="handlerClick(color)"
+        :selected="isSelected(color)"
+      />
+    </ul>
+  </div>
+</template>
+
+<script>
+import ColorDot from './ColorDot'
+
+export default {
+  name: 'va-simple-palette-picker',
+  components: {
+    ColorDot,
+  },
+  props: {
+    palette: {
+      type: Array,
+    },
+    value: {
+      default: '',
+    },
+  },
+  computed: {
+    valueProxy: {
+      get () {
+        return this.value
+      },
+      set (value) {
+        this.$emit('input', value)
+      },
+    },
+  },
+  methods: {
+    isSelected (color) {
+      return this.value === color
+    },
+    handlerClick (color) {
+      this.valueProxy = color
+    },
+  },
+}
+</script>
+
+<style lang="scss">
+.va-simple-palette-picker {
+  padding-top: 3px;
+
+  &__colors {
+    padding: 3px;
+    display: flex;
+  }
+}
+
+</style>
diff --git a/src/vuestic-theme/vuestic-components/va-color-picker/VaSliderColorPicker.demo.vue b/src/vuestic-theme/vuestic-components/va-color-picker/VaSliderColorPicker.demo.vue
new file mode 100644
index 0000000000000000000000000000000000000000..6a053682843a8594e9449409fe5c9607ae959e3e
--- /dev/null
+++ b/src/vuestic-theme/vuestic-components/va-color-picker/VaSliderColorPicker.demo.vue
@@ -0,0 +1,25 @@
+<template>
+  <div class="demo-container">
+    <div class="demo-container__item">
+      <va-slider-color-picker v-model="value"/>
+      <va-slider-color-picker v-model="value" style="padding-top: 20px"/>
+      {{value}}
+    </div>
+  </div>
+</template>
+
+<script>
+
+import VaSliderColorPicker from './VaSliderColorPicker'
+
+export default {
+  components: {
+    VaSliderColorPicker,
+  },
+  data () {
+    return {
+      value: '#34495e',
+    }
+  },
+}
+</script>
diff --git a/src/vuestic-theme/vuestic-components/va-color-picker/VaSliderColorPicker.vue b/src/vuestic-theme/vuestic-components/va-color-picker/VaSliderColorPicker.vue
new file mode 100644
index 0000000000000000000000000000000000000000..366468fc11074684e85367d9fa3316d88ae196f3
--- /dev/null
+++ b/src/vuestic-theme/vuestic-components/va-color-picker/VaSliderColorPicker.vue
@@ -0,0 +1,35 @@
+<template>
+  <SliderPicker v-model="valueProxy" class="vuestic-slider-picker"/>
+</template>
+
+<script>
+import { Slider } from 'vue-color'
+
+export default {
+  name: 'va-slider-color-picker',
+  components: {
+    'SliderPicker': Slider,
+  },
+  props: {
+    value: {
+      default: '',
+    },
+  },
+  computed: {
+    valueProxy: {
+      get () {
+        return this.value
+      },
+      set (value) {
+        this.$emit('input', value.hex)
+      },
+    },
+  },
+}
+</script>
+
+<style>
+.vuestic-slider-picker {
+  padding: 8px;
+}
+</style>
diff --git a/src/vuestic-theme/vuestic-components/vuestic-color-picker/VuesticAdvancedColorPicker.demo.vue b/src/vuestic-theme/vuestic-components/va-color-picker/VuesticAdvancedColorPicker.demo.vue
similarity index 100%
rename from src/vuestic-theme/vuestic-components/vuestic-color-picker/VuesticAdvancedColorPicker.demo.vue
rename to src/vuestic-theme/vuestic-components/va-color-picker/VuesticAdvancedColorPicker.demo.vue
diff --git a/src/vuestic-theme/vuestic-components/vuestic-color-picker/VuesticAdvancedColorPicker.vue b/src/vuestic-theme/vuestic-components/va-color-picker/VuesticAdvancedColorPicker.vue
similarity index 100%
rename from src/vuestic-theme/vuestic-components/vuestic-color-picker/VuesticAdvancedColorPicker.vue
rename to src/vuestic-theme/vuestic-components/va-color-picker/VuesticAdvancedColorPicker.vue
diff --git a/src/vuestic-theme/vuestic-components/vuestic-color-picker/VuesticColorDropdown.demo.vue b/src/vuestic-theme/vuestic-components/va-color-picker/VuesticColorDropdown.demo.vue
similarity index 100%
rename from src/vuestic-theme/vuestic-components/vuestic-color-picker/VuesticColorDropdown.demo.vue
rename to src/vuestic-theme/vuestic-components/va-color-picker/VuesticColorDropdown.demo.vue
diff --git a/src/vuestic-theme/vuestic-components/vuestic-color-picker/VuesticColorDropdown.vue b/src/vuestic-theme/vuestic-components/va-color-picker/VuesticColorDropdown.vue
similarity index 100%
rename from src/vuestic-theme/vuestic-components/vuestic-color-picker/VuesticColorDropdown.vue
rename to src/vuestic-theme/vuestic-components/va-color-picker/VuesticColorDropdown.vue
diff --git a/src/vuestic-theme/vuestic-components/vuestic-color-picker/VuesticColorInput.demo.vue b/src/vuestic-theme/vuestic-components/va-color-picker/VuesticColorInput.demo.vue
similarity index 100%
rename from src/vuestic-theme/vuestic-components/vuestic-color-picker/VuesticColorInput.demo.vue
rename to src/vuestic-theme/vuestic-components/va-color-picker/VuesticColorInput.demo.vue
diff --git a/src/vuestic-theme/vuestic-components/vuestic-color-picker/VuesticColorInput.vue b/src/vuestic-theme/vuestic-components/va-color-picker/VuesticColorInput.vue
similarity index 100%
rename from src/vuestic-theme/vuestic-components/vuestic-color-picker/VuesticColorInput.vue
rename to src/vuestic-theme/vuestic-components/va-color-picker/VuesticColorInput.vue
diff --git a/src/vuestic-theme/vuestic-components/vuestic-color-picker/VuesticColorPickerInput.demo.vue b/src/vuestic-theme/vuestic-components/va-color-picker/VuesticColorPickerInput.demo.vue
similarity index 100%
rename from src/vuestic-theme/vuestic-components/vuestic-color-picker/VuesticColorPickerInput.demo.vue
rename to src/vuestic-theme/vuestic-components/va-color-picker/VuesticColorPickerInput.demo.vue
diff --git a/src/vuestic-theme/vuestic-components/vuestic-color-picker/VuesticColorPickerInput.vue b/src/vuestic-theme/vuestic-components/va-color-picker/VuesticColorPickerInput.vue
similarity index 100%
rename from src/vuestic-theme/vuestic-components/vuestic-color-picker/VuesticColorPickerInput.vue
rename to src/vuestic-theme/vuestic-components/va-color-picker/VuesticColorPickerInput.vue
diff --git a/src/vuestic-theme/vuestic-components/vuestic-color-picker/VuesticColorSquare.vue b/src/vuestic-theme/vuestic-components/va-color-picker/VuesticColorSquare.vue
similarity index 100%
rename from src/vuestic-theme/vuestic-components/vuestic-color-picker/VuesticColorSquare.vue
rename to src/vuestic-theme/vuestic-components/va-color-picker/VuesticColorSquare.vue
diff --git a/src/vuestic-theme/vuestic-components/vuestic-color-picker/VuesticPalletCustom.demo.vue b/src/vuestic-theme/vuestic-components/va-color-picker/VuesticPalletCustom.demo.vue
similarity index 84%
rename from src/vuestic-theme/vuestic-components/vuestic-color-picker/VuesticPalletCustom.demo.vue
rename to src/vuestic-theme/vuestic-components/va-color-picker/VuesticPalletCustom.demo.vue
index e001b61da3261ec1cf7da67aef53bfe99e0d4743..447cac4a72eb0ce98ac5fe1eee31cd226b87037f 100644
--- a/src/vuestic-theme/vuestic-components/vuestic-color-picker/VuesticPalletCustom.demo.vue
+++ b/src/vuestic-theme/vuestic-components/va-color-picker/VuesticPalletCustom.demo.vue
@@ -10,7 +10,7 @@
 </template>
 
 <script>
-import { colorArray } from '../../../vuestic-theme/vuestic-components/vuestic-color-picker/VuesticTheme'
+import { colorArray } from './/VuesticTheme'
 
 import VuesticPalletCustom from './VuesticPalletCustom'
 
diff --git a/src/vuestic-theme/vuestic-components/vuestic-color-picker/VuesticPalletCustom.vue b/src/vuestic-theme/vuestic-components/va-color-picker/VuesticPalletCustom.vue
similarity index 100%
rename from src/vuestic-theme/vuestic-components/vuestic-color-picker/VuesticPalletCustom.vue
rename to src/vuestic-theme/vuestic-components/va-color-picker/VuesticPalletCustom.vue
diff --git a/src/vuestic-theme/vuestic-components/vuestic-color-picker/VuesticSimplePalettePicker.demo.vue b/src/vuestic-theme/vuestic-components/va-color-picker/VuesticSimplePalettePicker.demo.vue
similarity index 100%
rename from src/vuestic-theme/vuestic-components/vuestic-color-picker/VuesticSimplePalettePicker.demo.vue
rename to src/vuestic-theme/vuestic-components/va-color-picker/VuesticSimplePalettePicker.demo.vue
diff --git a/src/vuestic-theme/vuestic-components/vuestic-color-picker/VuesticSimplePalettePicker.vue b/src/vuestic-theme/vuestic-components/va-color-picker/VuesticSimplePalettePicker.vue
similarity index 100%
rename from src/vuestic-theme/vuestic-components/vuestic-color-picker/VuesticSimplePalettePicker.vue
rename to src/vuestic-theme/vuestic-components/va-color-picker/VuesticSimplePalettePicker.vue
diff --git a/src/vuestic-theme/vuestic-components/vuestic-color-picker/VuesticSliderColorPicker.demo.vue b/src/vuestic-theme/vuestic-components/va-color-picker/VuesticSliderColorPicker.demo.vue
similarity index 100%
rename from src/vuestic-theme/vuestic-components/vuestic-color-picker/VuesticSliderColorPicker.demo.vue
rename to src/vuestic-theme/vuestic-components/va-color-picker/VuesticSliderColorPicker.demo.vue
diff --git a/src/vuestic-theme/vuestic-components/vuestic-color-picker/VuesticSliderColorPicker.vue b/src/vuestic-theme/vuestic-components/va-color-picker/VuesticSliderColorPicker.vue
similarity index 100%
rename from src/vuestic-theme/vuestic-components/vuestic-color-picker/VuesticSliderColorPicker.vue
rename to src/vuestic-theme/vuestic-components/va-color-picker/VuesticSliderColorPicker.vue
diff --git a/src/vuestic-theme/vuestic-components/vuestic-color-picker/VuesticTheme.js b/src/vuestic-theme/vuestic-components/va-color-picker/VuesticTheme.js
similarity index 100%
rename from src/vuestic-theme/vuestic-components/vuestic-color-picker/VuesticTheme.js
rename to src/vuestic-theme/vuestic-components/va-color-picker/VuesticTheme.js
diff --git a/src/vuestic-theme/vuestic-components/va-dropdown/VaDropdown.demo.vue b/src/vuestic-theme/vuestic-components/va-dropdown/VaDropdown.demo.vue
index 588335e831cfdfea5f6b5cea08c3e6e29b37c56b..007109a08eda854b4b7d8259716a2e6c9bc588ad 100644
--- a/src/vuestic-theme/vuestic-components/va-dropdown/VaDropdown.demo.vue
+++ b/src/vuestic-theme/vuestic-components/va-dropdown/VaDropdown.demo.vue
@@ -110,6 +110,15 @@
       </template>
     </VbCard>
 
+    <VbCard title="Anchor width">
+      <va-dropdown keepAnchorWidth>
+        <button slot="anchor">
+          ------- Anchor ------
+        </button>
+        Same width as anchor
+      </va-dropdown>
+    </VbCard>
+
     <VbCard title="Disabled">
       <va-dropdown disabled>
         <button slot="anchor">
diff --git a/src/vuestic-theme/vuestic-components/va-dropdown/VaDropdown.vue b/src/vuestic-theme/vuestic-components/va-dropdown/VaDropdown.vue
index 0b504d9c267e6cead808784689c84beddf4e7a87..7f3a8adee9b1c8ac5a0dfbd5bf74850be4750bba 100644
--- a/src/vuestic-theme/vuestic-components/va-dropdown/VaDropdown.vue
+++ b/src/vuestic-theme/vuestic-components/va-dropdown/VaDropdown.vue
@@ -1,7 +1,7 @@
 <template>
-  <div class="va-dropdown-popper">
+  <div class="va-dropdown">
     <div
-      class="va-dropdown-popper__anchor"
+      class="va-dropdown__anchor"
       @mouseover="onMouseOver()"
       @mouseout="onMouseOut()"
       @click="onAnchorClick()"
@@ -10,14 +10,21 @@
       <slot name="anchor"/>
     </div>
     <div
-      class="va-dropdown-popper__content"
+      class="va-dropdown__content"
       v-if="showContent"
       @mouseover="isContentHoverable && onMouseOver()"
       @mouseout="onMouseOut()"
       ref="content"
-      :style="contentStyle"
     >
-      <slot/>
+      <div
+        v-if="keepAnchorWidth"
+        ref="anchorWidthContainer"
+        class="va-dropdown__anchor-width-container"
+        :style="anchorWidthContainerStyles"
+      >
+        <slot/>
+      </div>
+      <slot v-else/>
     </div>
   </div>
 </template>
@@ -32,6 +39,7 @@ export default {
     return {
       popperInstance: null,
       isClicked: false,
+      anchorWidth: undefined,
 
       isMouseHovered: false,
       hoverOverDebounceLoader: new DebounceLoader(
@@ -55,17 +63,14 @@ export default {
     this.unregisterClickOutsideListener()
     this.removePopper()
   },
+  mounted () {
+    this.handlePopperInstance()
+  },
   watch: {
     showContent: {
       immediate: true,
       handler (showContent) {
-        if (showContent && !this.popperInstance) {
-          this.$nextTick(() => {
-            this.initPopper()
-          })
-          return
-        }
-        this.removePopper()
+        this.handlePopperInstance()
       },
     },
   },
@@ -76,6 +81,7 @@ export default {
     offset: [String, Number],
     disabled: Boolean,
     fixed: Boolean,
+    keepAnchorWidth: Boolean, // Means dropdown width should be the same as anchor's width.
     closeOnClickOutside: {
       type: Boolean,
       default: true,
@@ -102,6 +108,22 @@ export default {
     },
   },
   methods: {
+    handlePopperInstance () {
+      if (this.popperInstance) {
+        this.removePopper()
+      }
+
+      if (!this.showContent) {
+        return
+      }
+
+      this.updateAnchorWidth()
+
+      // I'm not entirely sure why $nextTick is needed here.
+      this.$nextTick(() => {
+        this.initPopper()
+      })
+    },
     onAnchorClick () {
       this.$emit('anchorClick')
       if (this.disabled) {
@@ -160,6 +182,11 @@ export default {
       }
       this.hide()
     },
+    updateAnchorWidth () {
+      if (this.keepAnchorWidth) {
+        this.anchorWidth = this.$refs.anchor.offsetWidth
+      }
+    },
     // @public
     hide () {
       if (this.trigger === 'click') {
@@ -174,6 +201,9 @@ export default {
         arrow: {
           enabled: false,
         },
+        onUpdate: (data) => {
+          this.updateAnchorWidth()
+        },
       }
 
       if (this.offset) {
@@ -198,11 +228,19 @@ export default {
       this.popperInstance.destroy()
       this.popperInstance = null
     },
+    updatePopper () {
+      // used by select
+      if (!this.popperInstance) {
+        return
+      }
+      this.popperInstance.update()
+    },
   },
   computed: {
-    contentStyle () {
+    anchorWidthContainerStyles () {
       return {
-        padding: this.offset,
+        width: this.anchorWidth + 'px',
+        maxWidth: this.anchorWidth + 'px',
       }
     },
     showContent () {
@@ -214,7 +252,7 @@ export default {
       }
       if (this.trigger === 'none') {
         return this.value
-      } else return this.value
+      }
     },
   },
 }
@@ -223,7 +261,7 @@ export default {
 <style lang="scss">
 @import '../../vuestic-sass/resources/resources';
 
-.va-dropdown-popper {
+.va-dropdown {
   &__content {
     z-index: 100;
   }
diff --git a/src/vuestic-theme/vuestic-components/va-dropdown/dropdown-popover-docs.md b/src/vuestic-theme/vuestic-components/va-dropdown/dropdown-popover-docs.md
index 255f1a51c338c2d832e886b7261375405577f082..4571d4e16337d7b69e292360db588d863427cc23 100644
--- a/src/vuestic-theme/vuestic-components/va-dropdown/dropdown-popover-docs.md
+++ b/src/vuestic-theme/vuestic-components/va-dropdown/dropdown-popover-docs.md
@@ -27,19 +27,20 @@ For `hover` dropdown is shown only on hover, click does nothing.
 For `click` dropdown is shown on click and we handle click outside.
 For `none` no external handling is done. Instead we provide a prop `value` and a some events: `click`, `clickOutside`.
 
-* `isContentHoverable`: Boolean - default: `true`. Setting to false is useful for tooltips, where hanging dropdown become an obstacle.
-* `position`: String - default: 'bottom'. Appropriate values are 'top', 'bottom', 'left', 'right', 'auto', 'top-start', 'top-end' (and same for each direction). See [popper.js docs](https://popper.js.org/popper-documentation.html#Popper.placements) for details.
-* `fixed`: Boolean - default: `false`. Fixed dropdown works fine even if container is `position: relative; overflow: hidden`.
-* `disabled`: Boolean - default: `false`. Clicks and hovers won't do a thing.
-* `offset`: String - See [popper.js docs](https://popper.js.org/popper-documentation.html#modifiers..offset) for details.
-* value: Boolean - Used for passing down open/close state when trigger is 'none'.
+* `isContentHoverable` - Boolean - default: `true`. Setting to false is useful for tooltips, where hanging dropdown become an obstacle.
+* `position` - String - default: 'bottom'. Appropriate values are 'top', 'bottom', 'left', 'right', 'auto', 'top-start', 'top-end' (and same for each direction). See [popper.js docs](https://popper.js.org/popper-documentation.html#Popper.placements) for details.
+* `fixed` - Boolean - default: `false`. Fixed dropdown works fine even if container is `position: relative; overflow: hidden`.
+* `disabled` - Boolean - default: `false`. Clicks and hovers won't do a thing.
+* `offset` - String - See [popper.js docs](https://popper.js.org/popper-documentation.html#modifiers..offset) for details.
+* `value` - Boolean - default: `false`. Used for passing down open/close state when trigger is 'none'.
 
 #### Props (advanced)
 
-* `closeOnClickOutside`: Boolean - default: `true`. If set to `false`, click outside of dropdown won't close it. Useful for complex forms.
-* `closeOnAnchorClick`: Boolean - default: `true`. If set to `false`, click dropdown won't close on anchor click.
-* `hoverOverTimeout`: Number - default: 30. Hover dropdown will open after hovering for at least that value. Useful when you have a list with dropdowns and do not want to open every each of them on hover.
-* `hoverOutTimeout`: Number - default: 200. Hover dropdown will close after that timing. Allows to move cursor to content even with gaps in-between.
+* `closeOnClickOutside` - Boolean - default: `true`. If set to `false`, click outside of dropdown won't close it. Useful for complex forms.
+* `closeOnAnchorClick` - Boolean - default: `true`. If set to `false`, click dropdown won't close on anchor click.
+* `hoverOverTimeout` - Number - default: 30. Hover dropdown will open after hovering for at least that value. Useful when you have a list with dropdowns and do not want to open every each of them on hover.
+* `hoverOutTimeout` - Number - default: 200. Hover dropdown will close after that timing. Allows to move cursor to content even with gaps in-between.
+* `keepAnchorWidth` - Boolean - default: `false`. Dropdown should have the same width as anchor. Useful for selects.
 
 ### Additional things
 
diff --git a/src/vuestic-theme/vuestic-components/va-icon/VaIcon.demo.vue b/src/vuestic-theme/vuestic-components/va-icon/VaIcon.demo.vue
index 92710f06b90c5b8862ae60048a9311674f5bab32..d35eef5d5e7868ab90d20447f53e1f3af610104d 100644
--- a/src/vuestic-theme/vuestic-components/va-icon/VaIcon.demo.vue
+++ b/src/vuestic-theme/vuestic-components/va-icon/VaIcon.demo.vue
@@ -1,79 +1,87 @@
 <template>
   <VbDemo>
-    <VbContainer title="Default">
-      <va-icon :icon="icon"/>
-    </VbContainer>
+    <VbCard title="Default">
+      <va-icon :name="icon"/>
+    </VbCard>
 
-    <VbContainer title="Size in px">
-      <va-icon :icon="icon" size="40px"/>
-    </VbContainer>
+    <VbCard title="Size in px">
+      <va-icon :name="icon" size="40px"/>
+    </VbCard>
 
-    <VbContainer title="Size as number">
-      <va-icon :icon="icon" :size="60"/>
-    </VbContainer>
+    <VbCard title="Size as number">
+      <va-icon :name="icon" :size="60"/>
+    </VbCard>
 
-    <VbContainer title="Size presets">
+    <VbCard title="Size presets">
       <div style="font-size: 24px">
-        <va-icon :icon="icon" small/>
-        <va-icon :icon="icon"/>
-        <va-icon :icon="icon" large/>
+        <va-icon :name="icon" small/>
+        <va-icon :name="icon"/>
+        <va-icon :name="icon" large/>
       </div>
-    </VbContainer>
+    </VbCard>
 
-    <VbContainer title="Themes">
-      <va-icon :icon="icon" color="info"/>
-      <va-icon :icon="icon" color="warning"/>
-      <va-icon :icon="icon" color="danger"/>
-      <va-icon :icon="icon" color="success"/>
-      <va-icon :icon="icon" color="gray"/>
-      <va-icon :icon="icon" color="dark"/>
-    </VbContainer>
+    <VbCard title="Themes">
+      <va-icon :name="icon" color="info"/>
+      <va-icon :name="icon" color="warning"/>
+      <va-icon :name="icon" color="danger"/>
+      <va-icon :name="icon" color="success"/>
+      <va-icon :name="icon" color="gray"/>
+      <va-icon :name="icon" color="dark"/>
+    </VbCard>
 
-    <VbContainer title="Rotation">
-      <va-icon :icon="icon" :rotation="45"/>&nbsp;
-      <va-icon :icon="icon" :rotation="180"/>&nbsp;
-      <va-icon :icon="icon" :rotation="270"/>&nbsp;
-    </VbContainer>
+    <VbCard title="Rotation">
+      <va-icon :name="icon" :rotation="45"/>&nbsp;
+      <va-icon :name="icon" :rotation="180"/>&nbsp;
+      <va-icon :name="icon" :rotation="270"/>&nbsp;
+    </VbCard>
 
-    <VbContainer title="Fixed width">
-      <va-button :icon="icon" :icon-right="icon">
+    <VbCard title="Fixed width">
+      <va-button :name="icon" :icon-right="icon">
         Some
       </va-button>
-    </VbContainer>
+    </VbCard>
 
-    <VbContainer title="Iconic">
-      <va-icon icon="iconicstroke iconicstroke-hash"/>
-      <va-icon icon="iconicstroke iconicstroke-at"/>
-    </VbContainer>
-    <VbContainer title="Glyphicon">
-      <va-icon icon="glyphicon glyphicon-star"/>
-      <va-icon icon="glyphicon glyphicon-glass"/>
-    </VbContainer>
-    <VbContainer title="Maki">
-      <va-icon icon="maki maki-belowground-rail"/>
-      <va-icon icon="maki maki-bicycle"/>
-    </VbContainer>
-    <VbContainer title="Entypo">
-      <va-icon icon="entypo entypo-note"/>
-      <va-icon icon="entypo entypo-star"/>
-    </VbContainer>
-    <VbContainer title="Brandico">
-      <va-icon icon="brandico brandico-facebook"/>
-      <va-icon icon="brandico brandico-twitter"/>
-    </VbContainer>
-    <VbContainer title="Font Awesome">
-      <va-icon icon="fa fa-anchor"/>
-      <va-icon icon="fa fa-area-chart"/>
-    </VbContainer>
+    <VbCard title="Iconic">
+      <va-icon name="iconicstroke iconicstroke-hash"/>
+      <va-icon name="iconicstroke iconicstroke-at"/>
+    </VbCard>
+    <VbCard title="Glyphicon">
+      <va-icon name="glyphicon glyphicon-star"/>
+      <va-icon name="glyphicon glyphicon-glass"/>
+    </VbCard>
+    <VbCard title="Maki">
+      <va-icon name="maki maki-belowground-rail"/>
+      <va-icon name="maki maki-bicycle"/>
+    </VbCard>
+    <VbCard title="Entypo">
+      <va-icon name="entypo entypo-note"/>
+      <va-icon name="entypo entypo-star"/>
+    </VbCard>
+    <VbCard title="Brandico">
+      <va-icon name="brandico brandico-facebook"/>
+      <va-icon name="brandico brandico-twitter"/>
+    </VbCard>
+    <VbCard title="Font Awesome">
+      <va-icon name="fa fa-anchor"/>
+      <va-icon name="fa fa-area-chart"/>
+    </VbCard>
+    <VbCard title="Material design icons">
+      <va-icon name="material-icons">face</va-icon>
+      <va-icon name="material-icons">&#xE87C;</va-icon>
+      <va-icon name="material-icons" color="danger">face</va-icon>
+    </VbCard>
   </VbDemo>
 </template>
 
 <script>
 
 import VaIcon from './VaIcon'
+import VaButton from '../va-button/VaButton'
+
 export default {
   components: {
-    VaIcon
+    VaButton,
+    VaIcon,
   },
   data () {
     return {
diff --git a/src/vuestic-theme/vuestic-components/va-icon/VaIcon.vue b/src/vuestic-theme/vuestic-components/va-icon/VaIcon.vue
index 1818b2cae472eb73d2007b19ad3e780331c0850c..e0b7987d9419dfbdb3b4c6574ffe091b4473c8f3 100644
--- a/src/vuestic-theme/vuestic-components/va-icon/VaIcon.vue
+++ b/src/vuestic-theme/vuestic-components/va-icon/VaIcon.vue
@@ -1,36 +1,34 @@
 <template>
   <i class="va-icon"
-    :class="[icon, iconClass]"
-    :style="iconStyle"
-  />
+     :class="[name, iconClass]"
+     :style="iconStyle"
+  ><slot/></i>
 </template>
 
 <script>
 export default {
   name: 'va-icon',
   props: {
-    icon: {
-      type: [String, Array]
+    name: {
+      type: [String, Array],
     },
     small: {
       type: Boolean,
-      default: false
     },
     large: {
       type: Boolean,
-      default: false
     },
     size: {
       type: [String, Number],
     },
     fixedWidth: {
-      type: Boolean
+      type: Boolean,
     },
     rotation: {
-      type: [String, Number]
+      type: [String, Number],
     },
     color: {
-      type: String
+      type: String,
     },
   },
   computed: {
@@ -39,21 +37,16 @@ export default {
         'va-icon--large': this.large,
         'va-icon--small': this.small,
         'va-icon--fixed': this.fixedWidth,
-        'va-icon--success': this.color === 'success',
-        'va-icon--info': this.color === 'info',
-        'va-icon--danger': this.color === 'danger',
-        'va-icon--warning': this.color === 'warning',
-        'va-icon--gray': this.color === 'gray',
-        'va-icon--dark': this.color === 'dark',
       }
     },
     iconStyle () {
       return {
         transform: 'rotate(' + this.rotation + 'deg)',
-        fontSize: typeof this.size === 'number' ? this.size + 'px' : this.size
+        fontSize: typeof this.size === 'number' ? this.size + 'px' : this.size,
+        color: this.$themes[this.color] || this.color,
       }
-    }
-  }
+    },
+  },
 }
 </script>
 
diff --git a/src/vuestic-theme/vuestic-components/va-icon/va-icon.docs.md b/src/vuestic-theme/vuestic-components/va-icon/va-icon.docs.md
new file mode 100644
index 0000000000000000000000000000000000000000..fd31d647cb5fffdbb8778ce6548317f36d7de8e4
--- /dev/null
+++ b/src/vuestic-theme/vuestic-components/va-icon/va-icon.docs.md
@@ -0,0 +1,20 @@
+```html
+  <va-icon :name="iconicstroke iconicstroke-info"/>
+
+  <va-icon
+    :name="fa fa-anchor"
+    color="info"
+    rotation="45"
+    size="60"
+  />
+```
+
+***Props***
+* name - `String, Array` - The name of icon set and icon (will be used as class). We support Vuestic, Iconic, Glyphicon, Maki, Entypo, Brandico, Font Awesome, Material design icons. 
+* small - `Boolean` - If `small` prop is `true`, icon size will be 1rem (16px by default)
+* large - `Boolean` - If `large` prop is `true`, icon size will be 2.25rem
+* size - `String, Number` - Sets the custom size of icon in pixels
+* fixedWidth - `Boolean` - If `fixedWidth` prop is `true`, width of the icon will be 1.25rem
+* rotation - `String, Number` - Sets the degree of icons rotation.
+* color - `String` - Sets the color of icon
+
diff --git a/src/vuestic-theme/vuestic-components/va-icon/va-iconset/VaIconCleanCode.vue b/src/vuestic-theme/vuestic-components/va-icon/va-iconset/VaIconCleanCode.vue
index 36eb4fd5953201630985f7d579b332b099e32eba..3c05b38b4f91c7e2d39f7fc0f74b777cf87cab01 100644
--- a/src/vuestic-theme/vuestic-components/va-icon/va-iconset/VaIconCleanCode.vue
+++ b/src/vuestic-theme/vuestic-components/va-icon/va-iconset/VaIconCleanCode.vue
@@ -31,9 +31,11 @@ export default {
   display: inline-block;
   width: 56px;
   height: 50px;
+
   .cls-1 {
     fill: #4ae387;
   }
+
   .cls-2 {
     fill: #34495e;
   }
diff --git a/src/vuestic-theme/vuestic-components/va-icon/va-iconset/VaIconFree.vue b/src/vuestic-theme/vuestic-components/va-icon/va-iconset/VaIconFree.vue
index 28479bc4ab4a09ad4b0dbdd425301d3072bae7d2..dabe16e830a20a768e7cc242f51e4149f8ab06a2 100644
--- a/src/vuestic-theme/vuestic-components/va-icon/va-iconset/VaIconFree.vue
+++ b/src/vuestic-theme/vuestic-components/va-icon/va-iconset/VaIconFree.vue
@@ -28,15 +28,18 @@ export default {
   display: inline-block;
   width: 55px;
   height: 47.8px;
+
   .cls-1 {
     fill: #4ae387;
   }
+
   .cls-2 {
     fill: none;
     stroke: #34495e;
     stroke-miterlimit: 10;
     stroke-width: 3px;
   }
+
   .cls-3 {
     fill: #34495e;
   }
diff --git a/src/vuestic-theme/vuestic-components/va-icon/va-iconset/VaIconFresh.vue b/src/vuestic-theme/vuestic-components/va-icon/va-iconset/VaIconFresh.vue
index e11d9b107716ccf82b0c721d88168acff5d19c32..3ba0e6ed1cb03f8b004ea37a925d3665aa9f2a90 100644
--- a/src/vuestic-theme/vuestic-components/va-icon/va-iconset/VaIconFresh.vue
+++ b/src/vuestic-theme/vuestic-components/va-icon/va-iconset/VaIconFresh.vue
@@ -25,9 +25,11 @@ export default {
   display: inline-block;
   width: 51px;
   height: 48px;
+
   .cls-1 {
     fill: #4ae387;
   }
+
   .cls-2 {
     fill: #34495e;
   }
diff --git a/src/vuestic-theme/vuestic-components/va-icon/va-iconset/VaIconResponsive.vue b/src/vuestic-theme/vuestic-components/va-icon/va-iconset/VaIconResponsive.vue
index b6eb63add97468259a9a3802aede41ec1abc2e6e..7eb0792b23fe969d03de41d5aaef7fc75d9a8df7 100644
--- a/src/vuestic-theme/vuestic-components/va-icon/va-iconset/VaIconResponsive.vue
+++ b/src/vuestic-theme/vuestic-components/va-icon/va-iconset/VaIconResponsive.vue
@@ -26,9 +26,11 @@ export default {
   display: inline-block;
   width: 47.5px;
   height: 49px;
+
   .cls-1 {
     fill: #4ae387;
   }
+
   .cls-2 {
     fill: #34495e;
   }
diff --git a/src/vuestic-theme/vuestic-components/va-icon/va-iconset/VaIconRich.vue b/src/vuestic-theme/vuestic-components/va-icon/va-iconset/VaIconRich.vue
index b43193f8082b9556cb27cd23872bf470c0305ef8..624a4987b2b30def312afa90a9a91fd9a670b086 100644
--- a/src/vuestic-theme/vuestic-components/va-icon/va-iconset/VaIconRich.vue
+++ b/src/vuestic-theme/vuestic-components/va-icon/va-iconset/VaIconRich.vue
@@ -30,9 +30,11 @@ export default {
   display: inline-block;
   width: 57px;
   height: 55px;
+
   .cls-1 {
     fill: #4ae387;
   }
+
   .cls-2 {
     fill: #34495e;
   }
diff --git a/src/vuestic-theme/vuestic-components/va-icon/va-iconset/VaIconVue.vue b/src/vuestic-theme/vuestic-components/va-icon/va-iconset/VaIconVue.vue
index 6c7b65539ab4ab606484a72ce485005b924dedcb..6930fee1559cf033bded89af8c0cc0f06c0ab5a1 100644
--- a/src/vuestic-theme/vuestic-components/va-icon/va-iconset/VaIconVue.vue
+++ b/src/vuestic-theme/vuestic-components/va-icon/va-iconset/VaIconVue.vue
@@ -25,9 +25,11 @@ export default {
   display: inline-block;
   width: 55px;
   height: 47.8px;
+
   .cls-1 {
     fill: #4ae387;
   }
+
   .cls-2 {
     fill: #34495e;
   }
diff --git a/src/vuestic-theme/vuestic-components/va-input/VaInput.demo.vue b/src/vuestic-theme/vuestic-components/va-input/VaInput.demo.vue
index 0eece7756cb01b3962e776432f2c499551aeff0e..ef668ef46b9f3bb7c1989390a75f30d9952425b0 100644
--- a/src/vuestic-theme/vuestic-components/va-input/VaInput.demo.vue
+++ b/src/vuestic-theme/vuestic-components/va-input/VaInput.demo.vue
@@ -1,50 +1,55 @@
 <template>
   <VbDemo>
-    <VbContainer title="Design">
+    <VbCard title="Design">
       <div style="height: 200px; overflow-y: scroll">
         <img src="http://i68.tinypic.com/ne84fs.png" alt="">
       </div>
-    </VbContainer>
-    <VbContainer title="Input With Placeholder">
+    </VbCard>
+    <VbCard title="Placeholder">
       <va-input
         v-model="empty"
         placeholder="Name"
       />
-    </VbContainer>
-    <VbContainer title="Input With Label">
+    </VbCard>
+    <VbCard title="Label">
       <va-input
         v-model="text"
         label="Name"
       />
-    </VbContainer>
-    <VbContainer title="Input With Message">
+    </VbCard>
+    <VbCard title="Label long">
       <va-input
         v-model="text"
-        :messages="messages"/>
-    </VbContainer>
-    <VbContainer title="Disabled Input">
+        label="Name long long long long long long long long long long long long"
+      />
+    </VbCard>
+    <VbCard title="Message">
+      <va-input
+        v-model="text"
+        :messages="messages"
+      />
+    </VbCard>
+    <VbCard title="Disabled">
       <va-input
         v-model="text"
         disabled
       />
-    </VbContainer>
-    <VbContainer title="Readonly Input">
+    </VbCard>
+    <VbCard title="Readonly Input">
       <va-input
         v-model="text"
         readonly
       />
-    </VbContainer>
-    <VbContainer title="Input With Icon">
+    </VbCard>
+    <VbCard title="Icon">
       <va-input
         v-model="text"
         label="Name"
       >
-        <va-icon
-          icon="fa fa-anchor"
-        />
+        <va-icon name="fa fa-anchor"/>
       </va-input>
-    </VbContainer>
-    <VbContainer title="Input With Button">
+    </VbCard>
+    <VbCard title="Button">
       <va-input
         v-model="text"
         label="Name"
@@ -53,54 +58,84 @@
           Upload
         </va-button>
       </va-input>
-    </VbContainer>
-    <VbContainer title="Input With Prepend Slot">
+    </VbCard>
+    <VbCard title="Prepend Slot">
       <va-input
         v-model="text"
         label="Name"
       >
         <va-icon
           slot="prepend"
+          name="fa fa-anchor"
+        />
+      </va-input>
+    </VbCard>
+    <VbCard title="Append Slot">
+      <va-input
+        v-model="text"
+        label="Name"
+      >
+        <va-icon
+          slot="append"
           icon="fa fa-anchor"
         />
       </va-input>
-    </VbContainer>
-    <VbContainer title="Removable Icon">
+    </VbCard>
+    <VbCard title="Removable Icon">
       <va-input
         v-model="text"
         removable
       >
       </va-input>
-    </VbContainer>
-    <VbContainer title="Input With Error">
+    </VbCard>
+    <VbCard title="Error">
       <va-input
         v-model="text"
         label="Name"
         error
       />
-    </VbContainer>
-    <VbContainer title="Input With Success">
+    </VbCard>
+    <VbCard title="Success">
       <va-input
         v-model="text"
         label="Name"
         success
       />
-    </VbContainer>
-    <VbContainer title="Success and Removable">
+    </VbCard>
+    <VbCard title="Success and Removable">
       <va-input
         v-model="text"
         label="Name"
         removable
         success
+        :messages="successMessages"
+      />
+    </VbCard>
+    <VbCard title="Error Message">
+      <va-input
+        v-model="text"
+        label="Name"
+        error
+        :error-messages="errorMessages"
       />
-    </VbContainer>
-    <VbContainer title="Input With Error Message">
+    </VbCard>
+    <VbCard title="Error count 2">
       <va-input
         v-model="text"
         label="Name"
         error
-        :error-messages="errorMessages"/>
-    </VbContainer>
+        :errorCount="2"
+        :error-messages="['one', 'two']"
+      />
+    </VbCard>
+    <VbCard title="Textarea">
+      <va-input
+        v-model="text"
+        label="Name"
+        type="textarea"
+        rows="5"
+      />
+    </VbCard>
   </VbDemo>
 </template>
 
@@ -108,6 +143,7 @@
 import VaInput from './VaInput'
 import VaButton from './../va-button/VaButton'
 import VaIcon from './../va-icon/VaIcon'
+
 export default {
   components: {
     VaInput,
@@ -121,6 +157,7 @@ export default {
       phone: '33 310-86-24',
       messages: ['Required field'],
       errorMessages: ['Detailed error message'],
+      successMessages: ['Success message'],
     }
   },
 }
diff --git a/src/vuestic-theme/vuestic-components/va-input/VaInput.vue b/src/vuestic-theme/vuestic-components/va-input/VaInput.vue
index 2fb702bf19b6265ac1657b690a08adb3ab640396..67670fdbdfc30630960a6431a271ab988c275b6b 100644
--- a/src/vuestic-theme/vuestic-components/va-input/VaInput.vue
+++ b/src/vuestic-theme/vuestic-components/va-input/VaInput.vue
@@ -1,79 +1,99 @@
 <template>
   <va-input-wrapper
     class="va-input"
-    :class="{ 'va-input-wrapper--focused': isFocused }"
     :disabled="disabled"
-    :error="error"
     :success="success"
     :messages="messages"
+    :error="error"
     :error-messages="errorMessages"
+    :errorCount="errorCount"
   >
     <slot name="prepend" slot="prepend"/>
     <div
-      class="va-input__slot">
-      <label
-        :style="labelStyles"
-        aria-hidden="true"
-        class="va-input__slot__label"
+      class="va-input__container"
+      :class="{'va-input__container--textarea': isTextarea}"
+      :style="containerStyles"
+    >
+      <div
+        class="va-input__container__content-wrapper"
+        :style="{ paddingTop: label ? '' : '0'}"
       >
-        {{ label }}
-      </label>
-      <textarea
-        v-if="textarea"
-        :style="{ paddingBottom: label ? '0.125rem' : '0.875rem'}"
-        :aria-label="label"
-        :placeholder="placeholder"
-        :disabled="disabled"
-        :readonly="readonly"
-        :value="value"
-        v-on="inputListeners"
-      />
-      <input
-        v-else
-        :style="{ paddingBottom: label ? '0.125rem' : '0.875rem'}"
-        :aria-label="label"
-        :type="type"
-        :placeholder="placeholder"
-        :disabled="disabled"
-        :readonly="readonly"
-        :value="value"
-        v-on="inputListeners"
+        <label
+          :style="labelStyles"
+          aria-hidden="true"
+          class="va-input__container__label"
+        >
+          {{ label }}
+        </label>
+        <textarea
+          v-if="isTextarea"
+          class="va-input__container__input"
+          :style="textareaStyles"
+          :aria-label="label"
+          :placeholder="placeholder"
+          :disabled="disabled"
+          :readonly="readonly"
+          :value="value"
+          v-on="inputListeners"
+          v-bind="$attrs"
+        />
+        <input
+          v-else
+          class="va-input__container__input"
+          :style="{ paddingBottom: label ? '0.125rem' : '0.875rem' }"
+          :aria-label="label"
+          :type="type"
+          :placeholder="placeholder"
+          :disabled="disabled"
+          :readonly="readonly"
+          :value="value"
+          v-on="inputListeners"
+          v-bind="$attrs"
+        />
+      </div>
+      <div
+        v-if="success || error || $slots.append || (removable && hasContent)"
+        class="va-input__container__icon-wrapper"
       >
+        <va-icon
+          v-if="success"
+          class="va-input__container__icon"
+          name="fa fa-check"
+          color="success"
+        />
+        <va-icon
+          v-if="error"
+          class="va-input__container__icon"
+          name="fa fa-exclamation-triangle"
+          color="danger"
+        />
+        <slot name="append"/>
+        <va-icon
+          v-if="removable && hasContent"
+          @click.native="clearContent()"
+          class="va-input__container__close-icon"
+          :color="error ? 'danger': 'gray'"
+          name="ion ion-md-close ion"
+        />
+      </div>
     </div>
-    <va-icon
-      v-if="success"
-      slot="append"
-      icon="fa fa-check"
-      color="success"
-    />
-    <va-icon
-      v-if="error"
-      slot="append"
-      icon="fa fa-exclamation-triangle"
-      color="danger"
-    />
-    <slot slot="append"/>
-    <va-icon
-      v-if="removable && value.length"
-      @click.native="clearContent()"
-      slot="append"
-      class="va-input__close-icon"
-      :color="error ? 'danger': 'gray'"
-      icon="ion ion-md-close ion"
-    />
   </va-input-wrapper>
 </template>
 
 <script>
-import VaInputWrapper from '../va-input/VaInputWrapper'
+import VaInputWrapper from './VaInputWrapper'
 import VaIcon from '../va-icon/VaIcon'
+import {
+  getHoverColor,
+} from './../../../services/color-functions'
+
 export default {
   name: 'va-input',
   extends: VaInputWrapper,
   components: { VaInputWrapper, VaIcon },
   props: {
     value: {
-      type: String,
+      type: [String, Number],
     },
     label: {
       type: String,
@@ -94,9 +114,6 @@ export default {
     removable: {
       type: Boolean,
     },
-    textarea: {
-      type: Boolean
-    },
   },
   data () {
     return {
@@ -109,8 +126,30 @@ export default {
         color: this.error ? this.$themes.danger : '',
       }
     },
+    containerStyles () {
+      return {
+        backgroundColor:
+          this.error ? getHoverColor(this.$themes['danger'])
+            : this.success ? getHoverColor(this.$themes['success']) : '#f5f8f9',
+        borderColor:
+          this.error ? this.$themes.danger
+            : this.success ? this.$themes.success
+              : this.isFocused ? this.$themes.dark : this.$themes.gray,
+      }
+    },
+    textareaStyles () {
+      return {
+        paddingBottom: this.label ? '0.125rem' : '',
+        marginTop: this.label ? '0.875rem' : '',
+        paddingTop: this.label ? 0 : '',
+        minHeight: this.label ? '1.5rem' : '2.25rem',
+        marginBottom: 0,
+      }
+    },
     inputListeners () {
-      return Object.assign({},
+      // TODO Probably not the best idea to stick this in computed.
+      return Object.assign(
+        {},
         this.$listeners,
         {
           input: event => {
@@ -120,15 +159,13 @@ export default {
             this.$emit('click', event)
           },
           focus: event => {
-            /* eslint-disable vue/no-side-effects-in-computed-properties */
+            // eslint-disable-next-line vue/no-side-effects-in-computed-properties
             this.isFocused = true
-            /* eslint-enable vue/no-side-effects-in-computed-properties */
             this.$emit('focus', event)
           },
           blur: event => {
-            /* eslint-disable vue/no-side-effects-in-computed-properties */
+            // eslint-disable-next-line vue/no-side-effects-in-computed-properties
             this.isFocused = false
-            /* eslint-disable vue/no-side-effects-in-computed-properties */
             this.$emit('blur', event)
           },
           keyup: event => {
@@ -140,6 +177,12 @@ export default {
         }
       )
     },
+    hasContent () {
+      return ![null, undefined, ''].includes(this.value)
+    },
+    isTextarea () {
+      return this.type === 'textarea'
+    },
   },
   methods: {
     clearContent () {
@@ -150,55 +193,87 @@ export default {
 </script>
 
 <style lang='scss'>
-  @import '../../vuestic-sass/resources/resources';
-  .va-input {
-    &__slot {
+@import '../../vuestic-sass/resources/resources';
+
+.va-input {
+  &__container {
+    display: flex;
+    position: relative;
+    width: 100%;
+    min-height: 2.375rem;
+    border-style: solid;
+    border-width: 0 0 thin 0;
+    border-top-left-radius: 0.5rem;
+    border-top-right-radius: 0.5rem;
+
+    &__content-wrapper {
       display: flex;
-      position: relative;
+      align-items: flex-end;
       width: 100%;
-      &__label {
-        position: absolute;
-        bottom: 0.875rem;
-        left: 0.5rem;
-        width: 100%;
-        margin-bottom: 0.5rem;
-        color: $vue-green;
-        font-size: 0.625rem;
-        letter-spacing: 0.0375rem;
-        line-height: 1.2;
-        font-weight: bold;
-        text-transform: uppercase;
-      }
-      input, textarea {
-        width: 100%;
-        height: 1.5rem;
-        margin-bottom: 0.125rem;
-        padding: 0.25rem 0.5rem;
-        color: #34495e;
-        background-color: transparent;
-        border-style: none;
-        outline: none;
-        font-size: 1rem;
-        font-family: $font-family-sans-serif;
-        font-weight: normal;
-        font-style: normal;
-        font-stretch: normal;
-        line-height: 1.5;
-        letter-spacing: normal;
-        &::placeholder {
-          color: $brand-secondary;
-        }
-        &:placeholder-shown {
-          padding-bottom: 0.875rem;
-        }
-      }
+      /*min-width: 100%;*/
     }
-    textarea {
-      height: 3rem;
+
+    &__icon-wrapper {
+      display: flex;
+      align-items: center;
+      margin-right: 0.5rem;
     }
+
     &__close-icon {
       cursor: pointer;
       margin-left: 0.25rem;
     }
+
+    &__label {
+      position: absolute;
+      bottom: 0.875rem;
+      left: 0.5rem;
+      margin-bottom: 0.5rem;
+      max-width: calc(100% - 0.25rem);
+      color: $vue-green;
+      font-size: 0.625rem;
+      letter-spacing: 0.0375rem;
+      line-height: 1.2;
+      font-weight: bold;
+      text-transform: uppercase;
+      @include va-ellipsis();
+      transform-origin: top left;
+    }
+
+    &.va-input__container--textarea &__label {
+      bottom: auto;
+      top: 0.125rem;
+    }
+
+    &__input {
+      width: 100%;
+      height: 1.5rem;
+      margin-bottom: 0.125rem;
+      padding: 0.25rem 0.5rem;
+      color: #34495e;
+      background-color: transparent;
+      border-style: none;
+      outline: none;
+      font-size: 1rem;
+      font-family: $font-family-sans-serif;
+      font-weight: normal;
+      font-style: normal;
+      font-stretch: normal;
+      line-height: 1.5;
+      letter-spacing: normal;
+
+      &::placeholder {
+        color: $brand-secondary;
+      }
+
+      &:placeholder-shown {
+        padding-bottom: 0.875rem;
+      }
+    }
+
+    &.va-input__container--textarea &__input {
+      height: inherit;
+    }
   }
+}
 </style>
diff --git a/src/vuestic-theme/vuestic-components/va-input/VaInputWrapper.demo.vue b/src/vuestic-theme/vuestic-components/va-input/VaInputWrapper.demo.vue
index 0eece7756cb01b3962e776432f2c499551aeff0e..171dfe70b2c03eee272b6f827e34592c140dcd27 100644
--- a/src/vuestic-theme/vuestic-components/va-input/VaInputWrapper.demo.vue
+++ b/src/vuestic-theme/vuestic-components/va-input/VaInputWrapper.demo.vue
@@ -1,126 +1,81 @@
 <template>
   <VbDemo>
-    <VbContainer title="Design">
-      <div style="height: 200px; overflow-y: scroll">
-        <img src="http://i68.tinypic.com/ne84fs.png" alt="">
-      </div>
-    </VbContainer>
-    <VbContainer title="Input With Placeholder">
-      <va-input
-        v-model="empty"
-        placeholder="Name"
-      />
-    </VbContainer>
-    <VbContainer title="Input With Label">
-      <va-input
-        v-model="text"
-        label="Name"
-      />
-    </VbContainer>
-    <VbContainer title="Input With Message">
-      <va-input
-        v-model="text"
-        :messages="messages"/>
-    </VbContainer>
-    <VbContainer title="Disabled Input">
-      <va-input
-        v-model="text"
-        disabled
-      />
-    </VbContainer>
-    <VbContainer title="Readonly Input">
-      <va-input
-        v-model="text"
-        readonly
-      />
-    </VbContainer>
-    <VbContainer title="Input With Icon">
-      <va-input
-        v-model="text"
-        label="Name"
-      >
-        <va-icon
-          icon="fa fa-anchor"
-        />
-      </va-input>
-    </VbContainer>
-    <VbContainer title="Input With Button">
-      <va-input
-        v-model="text"
-        label="Name"
+    <VbCard title="Default">
+      <va-input-wrapper :messages="messages">
+        Input
+      </va-input-wrapper>
+    </VbCard>
+
+    <VbCard title="Slots scheme">
+      <va-input-wrapper :messages="messages">
+        <div slot="prepend" style="width: 30px; height: 30px; border: 1px dotted black;" class="flex-center">
+          <va-icon name="fa fa-volume-off"/>
+        </div>
+        <div style="width: 200px; height: 30px; border: 1px dotted black;">Default Slot</div>
+        <div slot="append" style="width: 30px; height: 30px; border: 1px dotted black;" class="flex-center">
+          <va-icon name="fa fa-volume-up"/>
+        </div>
+      </va-input-wrapper>
+    </VbCard>
+
+    <VbCard title="Error">
+      <va-input-wrapper
+        :errorMessages="errorMessages"
       >
-        <va-button style="margin-right: 0;" small>
-          Upload
-        </va-button>
-      </va-input>
-    </VbContainer>
-    <VbContainer title="Input With Prepend Slot">
-      <va-input
-        v-model="text"
-        label="Name"
+        <div>Default Slot</div>
+      </va-input-wrapper>
+    </VbCard>
+
+    <VbCard title="Error">
+      <va-input-wrapper
+        :errorMessages="errorMessages"
       >
-        <va-icon
-          slot="prepend"
-          icon="fa fa-anchor"
+        <div>Default Slot</div>
+      </va-input-wrapper>
+    </VbCard>
+
+    <VbCard title="Input Wrapper For Checkbox and Radio Button">
+      <va-input-wrapper :messages="messages">
+        <va-checkbox name="agree-to-terms" v-model="agreedToTerms">
+          <template slot="label">
+            {{ $t('auth.agree') }}
+            <a class="link" href="javascript:void(0);">{{ $t('auth.termsOfUse') }}</a>
+          </template>
+        </va-checkbox>
+      </va-input-wrapper>
+
+      <va-input-wrapper :messages="messages">
+        <va-radio-button
+          option="option1"
+          v-model="radioSelectedOption"
+          label="Radio"
         />
-      </va-input>
-    </VbContainer>
-    <VbContainer title="Removable Icon">
-      <va-input
-        v-model="text"
-        removable
-      >
-      </va-input>
-    </VbContainer>
-    <VbContainer title="Input With Error">
-      <va-input
-        v-model="text"
-        label="Name"
-        error
-      />
-    </VbContainer>
-    <VbContainer title="Input With Success">
-      <va-input
-        v-model="text"
-        label="Name"
-        success
-      />
-    </VbContainer>
-    <VbContainer title="Success and Removable">
-      <va-input
-        v-model="text"
-        label="Name"
-        removable
-        success
-      />
-    </VbContainer>
-    <VbContainer title="Input With Error Message">
-      <va-input
-        v-model="text"
-        label="Name"
-        error
-        :error-messages="errorMessages"/>
-    </VbContainer>
+      </va-input-wrapper>
+    </VbCard>
   </VbDemo>
 </template>
 
 <script>
-import VaInput from './VaInput'
+import VaInputWrapper from './VaInputWrapper'
 import VaButton from './../va-button/VaButton'
 import VaIcon from './../va-icon/VaIcon'
+import VaCheckbox from '../va-checkbox/VaCheckbox'
+
 export default {
   components: {
-    VaInput,
+    VaCheckbox,
+    VaInputWrapper,
     VaButton,
     VaIcon,
   },
   data () {
     return {
       empty: '',
+      agreedToTerms: false,
+      radioSelectedOption: false,
       text: 'Vuestic',
-      phone: '33 310-86-24',
       messages: ['Required field'],
-      errorMessages: ['Detailed error message'],
+      errorMessages: ['Detailed error message', 'Detailed error message', 'Detailed error message'],
     }
   },
 }
diff --git a/src/vuestic-theme/vuestic-components/va-input/VaInputWrapper.vue b/src/vuestic-theme/vuestic-components/va-input/VaInputWrapper.vue
index 410347a131de0f2795f427c996f8a982bb956c30..44a80d83eac697a4cf3e54858f889d2e626b7d87 100644
--- a/src/vuestic-theme/vuestic-components/va-input/VaInputWrapper.vue
+++ b/src/vuestic-theme/vuestic-components/va-input/VaInputWrapper.vue
@@ -1,68 +1,44 @@
-
 <template>
-  <div
-    class="va-input-wrapper"
-    :class="{ 'va-input-wrapper--disabled' : disabled }"
-  >
+  <div class="va-input-wrapper">
     <div class="va-input-wrapper__control">
       <div
         tabindex="0"
-        :style="slotStyles"
         class="va-input-wrapper__slot">
         <div
-          v-if="hasPrependData"
+          v-if="$slots.prepend"
           class="va-input-wrapper__prepend-inner">
           <slot name="prepend"/>
         </div>
         <div class="va-input-wrapper__content">
           <slot/>
+          <div class="va-input-wrapper__details py-0 px-2">
+            <va-message-list
+              :color="messagesColor"
+              :value="messagesComputed"
+              :limit="error ? errorCount : 99"
+            />
+          </div>
         </div>
         <div
-          v-if="hasAppendData"
+          v-if="$slots.append"
           class="va-input-wrapper__append-inner">
           <slot name="append"/>
         </div>
       </div>
-      <div class="va-input-wrapper__details py-0 px-2">
-        <div class="va-input-wrapper__messages">
-          <div
-            v-if="error"
-            :style="messageStyles"
-            class="va-input-wrapper__messages__wrapper">
-            <template
-              v-for="errorMessage in errorMessages">
-              {{ errorMessage }}
-            </template>
-          </div>
-          <div
-            v-else
-            :style="messageStyles"
-            class="va-input-wrapper__messages__wrapper">
-            <template v-for="message in messages">
-              {{ message }}
-            </template>
-          </div>
-        </div>
-      </div>
     </div>
   </div>
 </template>
 
 <script>
-import { getHoverColor } from './../../../services/color-functions'
+import VaMessageList from './VaMessageList'
 
 export default {
   name: 'va-input-wrapper',
+  components: { VaMessageList },
   props: {
-    disabled: {
-      type: Boolean,
-    },
-    error: {
-      type: Boolean,
-    },
-    success: {
-      type: Boolean,
-    },
+    disabled: Boolean,
+    error: Boolean,
+    success: Boolean,
     messages: {
       type: Array,
       default: () => [],
@@ -71,79 +47,71 @@ export default {
       type: Array,
       default: () => [],
     },
+    errorCount: {
+      type: Number,
+      default: 1,
+    },
   },
   computed: {
-    slotStyles () {
-      return {
-        backgroundColor: this.error ? getHoverColor(this.$themes['danger']) : this.success ? getHoverColor(this.$themes['success']) : '#f5f8f9',
-        borderColor: this.error ? this.$themes.danger : this.success ? this.$themes.success : this.$themes.gray,
-      }
-    },
-    messageStyles () {
-      return {
-        color: this.error ? this.$themes.danger : '#babfc2',
-      }
-    },
-    hasPrependData () {
-      return this.$slots.prepend
+    messagesComputed () {
+      return this.error ? this.errorMessages : this.messages
     },
-    hasAppendData () {
-      return this.$slots.append
+    messagesColor () {
+      return (this.error && 'danger') || (this.success && 'success') || ''
     },
   },
 }
 </script>
 
 <style lang='scss'>
-  @import '../../vuestic-sass/resources/resources';
-  .va-input-wrapper {
+@import '../../vuestic-sass/resources/resources';
+
+.va-input-wrapper {
+  display: flex;
+  flex: 1 1 auto;
+  align-items: flex-end;
+  font-size: 1rem;
+  text-align: left;
+  margin-bottom: 1rem;
+
+  &__control, &__content {
+    width: 100%;
+  }
+
+  &__content {
     display: flex;
-    flex: 1 1 auto;
-    align-items: flex-end;
-    font-size: 1rem;
-    text-align: left;
-    &--focused {
-      .va-input-wrapper__slot {
-        border-color: $charcoal !important;
-      }
-    }
-    &--disabled {
-      .va-input-wrapper__slot {
-        border-color: $brand-secondary !important;
-      }
-    }
-    &__control, &__content {
-      width: 100%;
-    }
-    &__content {
-      display: flex;
-      align-items: flex-end;
-    }
-    &__prepend-inner, &__append-inner {
-      display: inline-flex;
-      align-items: center;
-    }
-    &__prepend-inner {
-      margin-left: 0.5rem;
-    }
-    &__append-inner {
-      margin-right: 0.5rem;
-    }
-    &__slot {
-      display: flex;
-      position: relative;
-      min-height: 2.375rem;
-      border-style: solid;
-      border-width: 0 0 thin 0;
-      border-top-left-radius: 0.5rem;
-      border-top-right-radius: 0.5rem;
-      outline: none;
-    }
-    &__details {
-      padding: 0 0.5rem;
-    }
-    &__messages__wrapper {
-      font-size: 0.875rem;
-    }
+    flex-direction: column;
   }
+
+  &__prepend-inner, &__append-inner {
+    display: inline-flex;
+    align-items: center;
+  }
+
+  &__prepend-inner {
+    margin-right: 0.5rem;
+  }
+
+  &__append-inner {
+    margin-left: 0.5rem;
+  }
+
+  &__slot {
+    display: flex;
+    position: relative;
+    outline: none;
+  }
+
+  &__details {
+    padding: 0 0.5rem;
+    width: 100%;
+  }
+
+  &__messages__wrapper {
+    font-size: 0.875rem;
+  }
+  .va-select {
+    margin-bottom: 0;
+  }
+}
 </style>
diff --git a/src/vuestic-theme/vuestic-components/va-input/VaMessageList.demo.vue b/src/vuestic-theme/vuestic-components/va-input/VaMessageList.demo.vue
new file mode 100644
index 0000000000000000000000000000000000000000..9743f2a1f6f5798eecb2896a78257b3b1cbdc7e2
--- /dev/null
+++ b/src/vuestic-theme/vuestic-components/va-input/VaMessageList.demo.vue
@@ -0,0 +1,32 @@
+<template>
+  <VbDemo>
+    <VbCard title="Default">
+      <VaMessageList :value="stringMessage"/>
+    </VbCard>
+    <VbCard title="Message array">
+      <VaMessageList :limit="3" :value="stringMessages"/>
+    </VbCard>
+    <VbCard title="Error">
+      <VaMessageList color="danger" :value="stringMessages"/>
+    </VbCard>
+    <VbCard title="Success">
+      <VaMessageList color="success" :value="stringMessages"/>
+    </VbCard>
+  </VbDemo>
+</template>
+
+<script>
+import VaMessageList from './VaMessageList.vue'
+
+export default {
+  components: {
+    VaMessageList,
+  },
+  data () {
+    return {
+      stringMessage: 'String message',
+      stringMessages: ['Message', 'Another message', 'Long long long long long long long long long long long long long long error message'],
+    }
+  },
+}
+</script>
diff --git a/src/vuestic-theme/vuestic-components/va-input/VaMessageList.vue b/src/vuestic-theme/vuestic-components/va-input/VaMessageList.vue
new file mode 100644
index 0000000000000000000000000000000000000000..a9b29a2a63e3677b633200db367ceb9326e92e63
--- /dev/null
+++ b/src/vuestic-theme/vuestic-components/va-input/VaMessageList.vue
@@ -0,0 +1,60 @@
+<template>
+  <div
+    v-if="messages.length"
+    class="va-message-list"
+    :style="computedStyle"
+  >
+    <div
+      class="va-message-list__message"
+      v-for="(message, index) in messages"
+      :key="index"
+    >
+      {{message}}
+    </div>
+  </div>
+</template>
+
+<script>
+import { ColorThemeMixin } from '../../../services/ColorThemePlugin'
+
+export default {
+  name: 'va-message-list',
+  mixins: [ColorThemeMixin],
+  data () {
+    return {
+      colorThemeDefault: 'gray', // mixin override
+    }
+  },
+  props: {
+    value: {},
+    limit: { type: Number, default: 1 },
+  },
+  computed: {
+    messages () {
+      if (!this.value) {
+        return []
+      }
+      if (!Array.isArray(this.value)) {
+        return [this.value]
+      }
+      return this.value.slice(0, this.limit)
+    },
+    computedStyle () {
+      return {
+        color: this.colorComputed,
+      }
+    },
+  },
+}
+</script>
+
+<style lang="scss">
+@import "../../vuestic-sass/resources/resources";
+
+.va-message-list {
+  &__message {
+    vertical-align: middle;
+    font-size: $font-size-mini;
+  }
+}
+</style>
diff --git a/src/vuestic-theme/vuestic-components/va-input/message-list-docs.md b/src/vuestic-theme/vuestic-components/va-input/message-list-docs.md
new file mode 100644
index 0000000000000000000000000000000000000000..1b5e46f3a2653da459e8e1cfefc668ecad0dcf17
--- /dev/null
+++ b/src/vuestic-theme/vuestic-components/va-input/message-list-docs.md
@@ -0,0 +1,7 @@
+## Gist 
+
+Message list is intended as internal component for displaying consistently list of messages.
+
+It is used in various input components to show descriptions and error messages.
+
+This component can be used as standalone in form component to show form-specific messages.
diff --git a/src/vuestic-theme/vuestic-components/va-progress-bar/progress-types/VaProgressBar.vue b/src/vuestic-theme/vuestic-components/va-progress-bar/progress-types/VaProgressBar.vue
index 5c1a64ef27999505b5661911facde5bae332ca32..75ab235c78c10038355e1fdbd6b7785edafd1a68 100644
--- a/src/vuestic-theme/vuestic-components/va-progress-bar/progress-types/VaProgressBar.vue
+++ b/src/vuestic-theme/vuestic-components/va-progress-bar/progress-types/VaProgressBar.vue
@@ -29,7 +29,7 @@
 
 <script>
 import { progressMixin } from './progressMixin'
-import utils from '../../../../services/utils'
+import utils from '../../../../utils/utils'
 
 export default {
   name: 'va-progress-bar',
diff --git a/src/vuestic-theme/vuestic-components/va-progress-bar/progress-types/progressMixin.js b/src/vuestic-theme/vuestic-components/va-progress-bar/progress-types/progressMixin.js
index 8901f817b7501a5b93e5b6ea468091f3ad72896c..5ed728430fbb2767f81fee205b0073dbd98868dd 100644
--- a/src/vuestic-theme/vuestic-components/va-progress-bar/progress-types/progressMixin.js
+++ b/src/vuestic-theme/vuestic-components/va-progress-bar/progress-types/progressMixin.js
@@ -1,8 +1,8 @@
-import utils from '../../../../services/utils'
+import utils from '../../../../utils/utils'
 import {
   colorConfig,
   VuesticTheme
-} from './../../vuestic-color-picker/VuesticTheme'
+} from '../../va-color-picker/VuesticTheme'
 
 export const progressMixin = {
   props: {
diff --git a/src/vuestic-theme/vuestic-components/vuestic-radio-button/VuesticRadioButton.demo.vue b/src/vuestic-theme/vuestic-components/va-radio-button/VaRadioButton.demo.vue
similarity index 87%
rename from src/vuestic-theme/vuestic-components/vuestic-radio-button/VuesticRadioButton.demo.vue
rename to src/vuestic-theme/vuestic-components/va-radio-button/VaRadioButton.demo.vue
index 2d70f28b4246af90bbb85585ae9c7216bd03a0db..f6c39fe78c9d26760170c0f8a3b501053ff1f19c 100644
--- a/src/vuestic-theme/vuestic-components/vuestic-radio-button/VuesticRadioButton.demo.vue
+++ b/src/vuestic-theme/vuestic-components/va-radio-button/VaRadioButton.demo.vue
@@ -1,7 +1,7 @@
 <template>
   <div class="demo-container">
     <div class="demo-container__item">
-      <vuestic-radio-button
+      <va-radio-button
         v-for="(option, index) in options"
         :key="index"
         v-model="selectedOptionString"
@@ -9,7 +9,7 @@
       />
     </div>
     <div class="demo-container__item">
-      <vuestic-radio-button
+      <va-radio-button
         v-for="(option, index) in options"
         :key="index"
         v-model="selectedOptionString"
@@ -18,7 +18,7 @@
       />
     </div>
     <div class="demo-container__item">
-      <vuestic-radio-button
+      <va-radio-button
         v-for="(option, index) in options"
         :key="index"
         v-model="selectedOptionString"
@@ -31,7 +31,7 @@
     </div>
 
     <div class="demo-container__item">
-      <vuestic-radio-button
+      <va-radio-button
         v-for="option in objectOptions"
         :key="option.key"
         v-model="selectedOptionObject"
@@ -44,10 +44,10 @@
 </template>
 
 <script>
-import VuesticRadioButton from './VuesticRadioButton'
+import VaRadioButton from './VaRadioButton'
 
 export default {
-  components: { VuesticRadioButton },
+  components: { VaRadioButton },
   data () {
     const objectOptions = [
       { key: 1, name: 'one' },
diff --git a/src/vuestic-theme/vuestic-components/vuestic-radio-button/VuesticRadioButton.vue b/src/vuestic-theme/vuestic-components/va-radio-button/VaRadioButton.vue
similarity index 73%
rename from src/vuestic-theme/vuestic-components/vuestic-radio-button/VuesticRadioButton.vue
rename to src/vuestic-theme/vuestic-components/va-radio-button/VaRadioButton.vue
index 8180473d7f83236c0a1ef6a32c13dbf7f4f65dc5..fe03ed1b82c0c6f1530e2e42b1fed85c3457f565 100644
--- a/src/vuestic-theme/vuestic-components/vuestic-radio-button/VuesticRadioButton.vue
+++ b/src/vuestic-theme/vuestic-components/va-radio-button/VaRadioButton.vue
@@ -1,11 +1,11 @@
 <template>
   <div
-    class="vuestic-radio-button"
+    class="va-radio-button"
     :class="computedClass"
     @click="onClick"
   >
     <div
-      class="vuestic-radio-button__content"
+      class="va-radio-button__content"
       @mousedown="focused = false"
       @mouseup="focused = false"
       :class="{'active': isActive}"
@@ -14,14 +14,14 @@
         @focus="focused = true"
         @mouseout="focused = false"
         @blur="focused = false"
-        :checked="isActive" type="radio" class="vuestic-radio-button__input"
+        :checked="isActive" type="radio" class="va-radio-button__input"
         :disabled="disabled"
       />
-      <div class="vuestic-radio-button__icon">
-        <div class="vuestic-radio-button__icon-circle"/>
+      <div class="va-radio-button__icon">
+        <div class="va-radio-button__icon-circle"/>
       </div>
     </div>
-    <div class="vuestic-radio-button__slot-container">
+    <div class="va-radio-button__slot-container">
       <slot name="label">
         {{ computedLabel }}
       </slot>
@@ -32,7 +32,7 @@
 <script>
 
 export default {
-  name: 'vuestic-radio-button',
+  name: 'va-radio-button',
   props: {
     value: [Boolean, String, Number],
     option: [String, Boolean, Number],
@@ -44,15 +44,15 @@ export default {
   },
   data () {
     return {
-      isFocused: false
+      isFocused: false,
     }
   },
   computed: {
     computedClass () {
       return {
-        'vuestic-radio-button--active': this.isActive,
-        'vuestic-radio-button--disabled': this.disabled,
-        'vuestic-radio-button--on-focus': this.focused
+        'va-radio-button--active': this.isActive,
+        'va-radio-button--disabled': this.disabled,
+        'va-radio-button--on-focus': this.focused,
       }
     },
     focused: {
@@ -63,7 +63,7 @@ export default {
       },
       get () {
         return this.isFocused
-      }
+      },
     },
     computedLabel () {
       if (!this.label) {
@@ -73,7 +73,7 @@ export default {
     },
     isActive () {
       return this.value === this.option
-    }
+    },
   },
   methods: {
     onClick () {
@@ -88,29 +88,30 @@ export default {
 <style lang="scss">
 @import "../../vuestic-sass/resources/resources";
 
-.vuestic-radio-button {
+.va-radio-button {
   cursor: pointer;
   display: flex;
   flex-direction: row;
-  margin-bottom: $checkbox-between-items-margin;
+
   &__icon {
     width: 1.4rem;
     height: 1.4rem;
     border-radius: 1.8rem;
     border: $gray solid 0.15rem;
     @at-root {
-      .vuestic-radio-button.vuestic-radio-button--active & {
+      .va-radio-button.va-radio-button--active & {
         border: $vue-green solid 0.15rem;
       }
 
-      .vuestic-radio-button.vuestic-radio-button--disabled & {
+      .va-radio-button.va-radio-button--disabled & {
         opacity: 0.4;
       }
     }
   }
+
   &__icon-circle {
     @at-root {
-      .vuestic-radio-button.vuestic-radio-button--active & {
+      .va-radio-button.va-radio-button--active & {
         width: 0.625rem;
         height: 0.625rem;
         border-radius: 1rem;
@@ -120,6 +121,7 @@ export default {
       }
     }
   }
+
   &__input {
     width: 1.375rem;
     height: 1.375rem;
@@ -127,6 +129,7 @@ export default {
     cursor: pointer;
     opacity: 0;
   }
+
   #{&}__content {
     width: 32px;
     height: 32px;
@@ -134,16 +137,18 @@ export default {
     align-items: center;
     justify-content: center;
     @at-root {
-      .vuestic-radio-button--on-focus#{&} {
+      .va-radio-button--on-focus#{&} {
         background-color: $light-gray;
         transition: all, 0.6s, ease-in;
         border-radius: 3rem;
+
         &.active {
           background-color: $lighter-green;
         }
       }
     }
   }
+
   &__slot-container {
     padding-top: $checkbox-label-margin-top;
   }
diff --git a/src/vuestic-theme/vuestic-components/va-select/VaSelect.demo.vue b/src/vuestic-theme/vuestic-components/va-select/VaSelect.demo.vue
new file mode 100644
index 0000000000000000000000000000000000000000..ab3af1b9c8858cd1986532b4fd407186d732adee
--- /dev/null
+++ b/src/vuestic-theme/vuestic-components/va-select/VaSelect.demo.vue
@@ -0,0 +1,265 @@
+<template>
+  <VbDemo>
+    <VbCard title="String options (default)" style="width: 400px;">
+      <va-select
+        :options="defaultSelect.options"
+        v-model="defaultSelect.value"
+      />
+    </VbCard>
+    <VbCard title="error" style="width: 400px;">
+      <va-select
+        :options="defaultSelect.options"
+        v-model="defaultSelect.value"
+        error
+      />
+      <va-select
+        :options="defaultSelect.options"
+        v-model="defaultSelect.value"
+        success
+      />
+      <va-input-wrapper
+        error
+        :errorMessages="['error message']"
+      >
+        <va-select
+          :options="defaultSelect.options"
+          v-model="defaultSelect.value"
+          error
+        />
+      </va-input-wrapper>
+    </VbCard>
+    <VbCard title="Object options" style="width: 400px;">
+      <va-select
+        label="Object value"
+        v-model="objectSelect.value"
+        :options="objectSelect.options"
+      />
+      <p>key-by='value'</p>
+      <va-select
+        v-model="iconsSelect.value"
+        :options="iconsSelect.options"
+        key-by="value"
+      />
+      <p>textBy='icon'</p>
+      <va-select
+        text-by="icon"
+        v-model="iconsSelect.value"
+        :options="iconsSelect.options"
+      />
+      <p>key-by='value' (multiple)</p>
+      <va-select
+        key-by="value"
+        v-model="multipleValue"
+        :options="iconsSelect.options"
+        multiple
+      />
+    </VbCard>
+    <VbCard title="Options with icons" style="width: 400px;">
+      <va-select
+        v-model="iconsSelect.value"
+        :options="iconsSelect.options"
+      />
+    </VbCard>
+    <VbCard title="No options" style="width: 400px;">
+      <va-select
+        v-model="defaultSelect.value"
+        :options="[]"
+      />
+      <va-select
+        label="custom no options text"
+        v-model="defaultSelect.value"
+        :options="[]"
+        no-options-text="Sorry..."
+      />
+    </VbCard>
+    <VbCard title="Custom clear value" style="width: 400px;">
+      <va-select
+        v-model="defaultSelect.value"
+        clear-value="1"
+        :options="defaultSelect.options"
+      />
+    </VbCard>
+    <VbCard title="No clear" style="width: 400px;">
+      <va-select
+        v-model="defaultSelect.value"
+        :options="defaultSelect.options"
+        no-clear
+      />
+    </VbCard>
+    <VbCard title="Placeholder" style="width: 400px;">
+      <va-select
+        v-model="defaultSelect.value"
+        :options="CountriesList"
+        placeholder="select country"
+      />
+      <va-select
+        v-model="defaultSelect.value"
+        :options="CountriesList"
+        placeholder="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,"
+      />
+    </VbCard>
+    <VbCard title="Label" style="width: 400px;">
+      <va-select
+        label="country label"
+        v-model="defaultSelect.value"
+        :options="CountriesList"
+      />
+    </VbCard>
+    <VbCard title="Label and placeholder" style="width: 400px;">
+      <va-select
+        label="country label"
+        placeholder="select country"
+        v-model="defaultSelect.value"
+        :options="CountriesList"
+      />
+    </VbCard>
+    <VbCard title="positions" style="width: 400px;">
+      <div v-for="position in positions" :key="position">
+        <p>{{position}}</p>
+        <va-select
+          :position="position"
+          v-model="defaultSelect.value"
+          :options="CountriesList"
+        />
+      </div>
+    </VbCard>
+    <VbCard title="disabled" style="width: 400px;">
+      <va-select
+        v-model="defaultSelect.value"
+        :options="CountriesList"
+        disabled
+      />
+    </VbCard>
+    <VbCard title="multiple" style="width: 400px;">
+      <va-select
+        v-model="multipleValue"
+        multiple
+        :options="CountriesList"
+      />
+      <va-select
+        label="with custom tag-max"
+        v-model="multipleValue"
+        multiple
+        :tagMax="8"
+        :options="CountriesList"
+      />
+    </VbCard>
+    <VbCard title="searchable" style="width: 400px;">
+      <va-select
+        v-model="defaultSelect.value"
+        :options="CountriesList"
+        searchable
+      />
+    </VbCard>
+    <VbCard title="searchable + multiple" style="width: 400px;">
+      <va-select
+        v-model="multipleValue"
+        :options="CountriesList"
+        searchable
+        multiple
+      />
+    </VbCard>
+    <VbCard title="custom max-height (320px)" style="width: 400px;">
+      <va-select
+        v-model="defaultSelect.value"
+        :options="CountriesList"
+        max-height="320px"
+      />
+    </VbCard>
+    <VbCard title="custom width (30%)" :style="{'width': '100%'}" style="width: 400px;">
+      <va-select
+        v-model="defaultSelect.value"
+        :options="CountriesList"
+        width="30%"
+      />
+      <va-select
+        v-model="defaultSelect.value"
+        :options="CountriesList"
+        width="120px"
+      />
+    </VbCard>
+    <VbCard title="loading" style="width: 400px;">
+      <va-select
+        v-model="defaultSelect.value"
+        :options="CountriesList"
+        loading
+      />
+    </VbCard>
+    <VbCard title="with ajax" style="width: 400px;">
+      <va-select
+        searchable
+        v-model="defaultSelect.value"
+        :options="CountriesList"
+        :loading="isLoading"
+        @update-search="updateSearch"
+      />
+    </VbCard>
+    <VbCard title="long textes" style="width: 400px">
+      <va-select
+        searchable
+        placeholder="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,"
+        label="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,"
+        v-model="longSelect.value"
+        :options="longSelect.options"
+      />
+    </VbCard>
+    <VbCard :style="{ 'width': '100%' }">
+      <p>{{defaultSelect.value}}</p>
+      <p>{{objectSelect.value}}</p>
+      <p>{{iconsSelect.value}}</p>
+      <p>{{multipleValue}}</p>
+      <p>{{longSelect.value}}</p>
+    </VbCard>
+  </VbDemo>
+</template>
+
+<script>
+
+import CountriesList from '../../../data/CountriesList'
+import VaSelect from './VaSelect'
+import VaInputWrapper from '../va-input/VaInputWrapper'
+import { objectOptionsList, iconOptionsList } from './getDemoData'
+
+const positions = ['top', 'bottom']
+
+export default {
+  components: { VaInputWrapper, VaSelect },
+  data () {
+    return {
+      defaultSelect: {
+        options: ['one', 'two', 'three'],
+        value: 'one',
+      },
+      objectSelect: {
+        value: '',
+        options: objectOptionsList,
+      },
+      iconsSelect: {
+        value: '',
+        options: iconOptionsList,
+      },
+      longSelect: {
+        value: '1st long long long long option sit amet, consectetur adipiscing elit,',
+        options: [
+          '1st long long long long option sit amet, consectetur adipiscing elit,',
+          '2nd long  sit amet, consectetur adipiscing elit, long long long long long option',
+        ],
+      },
+      multipleValue: [],
+      CountriesList,
+      positions,
+      isLoading: false,
+    }
+  },
+  methods: {
+    updateSearch (val) {
+      this.isLoading = true
+      setTimeout(() => {
+        this.isLoading = false
+        // eslint-disable-next-line no-console
+        console.log(val)
+      }, 2000)
+    },
+  },
+}
+</script>
diff --git a/src/vuestic-theme/vuestic-components/va-select/VaSelect.vue b/src/vuestic-theme/vuestic-components/va-select/VaSelect.vue
new file mode 100644
index 0000000000000000000000000000000000000000..a6b68326db1c1854ee15ed9e5f1d043fec1fa45e
--- /dev/null
+++ b/src/vuestic-theme/vuestic-components/va-select/VaSelect.vue
@@ -0,0 +1,526 @@
+<template>
+  <va-dropdown
+    :position="position"
+    :disabled="disabled"
+    class="va-select__dropdown"
+    :max-height="maxHeight"
+    keepAnchorWidth
+    ref="dropdown"
+    :fixed="fixed"
+    :style="{width}"
+    :closeOnAnchorClick="false"
+  >
+    <va-input
+      v-if="searchable"
+      :placeholder="placeholder"
+      v-model="search"
+      class="va-select__input"
+      ref="search"
+      removable
+    />
+    <ul
+      class="va-select__option-list"
+      :style="optionsListStyle"
+    >
+      <li
+        v-for="option in filteredOptions"
+        :key="getKey(option)"
+        :class="getOptionClass(option)"
+        :style="getOptionStyle(option)"
+        @click.stop="selectOption(option)"
+        @mouseleave="updateHoveredOption(null)"
+        @mouseover="updateHoveredOption(option)"
+      >
+        <va-icon v-show="option.icon" :name="option.icon" class="va-select__option__icon"/>
+        <span>{{getText(option)}}</span>
+        <va-icon
+          v-show="isSelected(option)"
+          class="va-select__option__selected-icon"
+          name="material-icons">
+          done
+        </va-icon>
+      </li>
+    </ul>
+    <div
+      class="va-select__option-list no-options"
+      :style="optionsListStyle"
+      v-if="!filteredOptions.length"
+    >
+      {{noOptionsText}}
+    </div>
+
+    <div
+      slot="anchor"
+      :class="selectClass"
+      :style="selectStyle"
+    >
+      <label
+        class="va-select__label"
+        :style="{ color: $themes.success }"
+        aria-hidden="true"
+      >{{label}}</label>
+      <div
+        class="va-select__input-wrapper"
+        :style="inputWrapperStyles"
+      >
+        <span
+          class="va-select__tags"
+          v-if="multiple && valueProxy.length <= tagMax"
+        >
+          <va-chip
+            v-for="option in valueProxy"
+            :key="getKey(option)"
+            small
+          >
+            {{getText(option)}}
+          </va-chip>
+        </span>
+        <span v-else-if="displayedText" class="va-select__displayed-text">{{displayedText}}</span>
+        <span v-else class="va-select__placeholder">{{placeholder}}</span>
+      </div>
+      <va-icon
+        v-if="showClearIcon"
+        class="va-select__clear-icon"
+        name="fa fa-times-circle"
+        @click.native.stop="clear()"
+      />
+      <spring-spinner
+        :color="$themes.success"
+        v-if="loading"
+        :size="24"
+        class="va-select__loading"
+      />
+      <va-icon
+        class="va-select__open-icon"
+        :name="visible ? 'fa fa-chevron-up' : 'fa fa-chevron-down'"
+      />
+    </div>
+  </va-dropdown>
+</template>
+
+<script>
+import VaDropdown from '../va-dropdown/VaDropdown'
+import VaChip from '../va-chip/VaChip'
+import { SpringSpinner } from 'epic-spinners'
+import VaIcon from '../va-icon/VaIcon'
+import VaInput from '../va-input/VaInput'
+import { getHoverColor } from '../../../services/color-functions'
+
+const positions = {
+  'top': 'T',
+  'bottom': 'B',
+}
+export default {
+  name: 'va-select',
+  components: { VaIcon, SpringSpinner, VaDropdown, VaChip, VaInput },
+  data () {
+    return {
+      search: '',
+      mounted: false,
+      hoveredOption: null,
+    }
+  },
+  props: {
+    value: {},
+    label: String,
+    placeholder: String,
+    options: {
+      type: Array,
+      default: () => [],
+    },
+    position: {
+      type: String,
+      default: 'bottom',
+      validator: position => Object.keys(positions).includes(position),
+    },
+    tagMax: {
+      type: Number,
+      default: 5,
+    },
+    searchable: Boolean,
+    multiple: Boolean,
+    disabled: Boolean,
+    readonly: Boolean,
+    loading: Boolean,
+    width: {
+      type: String,
+      default: '100%',
+    },
+    maxHeight: {
+      type: String,
+      default: '128px',
+    },
+    keyBy: {
+      type: String,
+      default: 'id',
+    },
+    textBy: {
+      type: String,
+      default: 'text',
+    },
+    clearValue: {
+      default: '',
+    },
+    noOptionsText: {
+      type: String,
+      default: 'Items not found',
+    },
+    fixed: {
+      type: Boolean,
+      default: true,
+    },
+    noClear: Boolean,
+    error: Boolean,
+    success: Boolean,
+  },
+  watch: {
+    search (val) {
+      this.$emit('update-search', val)
+    },
+    visible (val) {
+      if (val && this.searchable) {
+        this.$nextTick(() => {
+          this.$refs.search.$refs.input.focus()
+        })
+      }
+    },
+  },
+  computed: {
+    visible () {
+      return this.mounted ? this.$refs.dropdown.isClicked : false
+    },
+    selectClass () {
+      return {
+        'va-select': true,
+        'va-select--multiple': this.multiple,
+        'va-select--visible': this.visible,
+        'va-select--searchable': this.searchable,
+        'va-select--disabled': this.disabled,
+        'va-select--loading': this.loading,
+      }
+    },
+    selectStyle () {
+      return {
+        backgroundColor:
+          this.error ? getHoverColor(this.$themes['danger'])
+            : this.success ? getHoverColor(this.$themes['success']) : '#f5f8f9',
+        borderColor:
+          this.error ? this.$themes.danger
+            : this.success ? this.$themes.success
+              : this.$themes.gray,
+      }
+    },
+    optionsListStyle () {
+      return { maxHeight: this.maxHeight }
+    },
+    displayedText () {
+      if (!this.valueProxy) {
+        return ''
+      }
+      if (this.multiple) {
+        return this.valueProxy.length ? `${this.valueProxy.length} items selected` : ''
+      }
+      // We try to find a match from options, if we don't find any - we take value.
+      // This way select can display value even when options are not loaded yet.
+      const selectedOption = this.valueProxy || this.selectedOption
+      const isString = typeof selectedOption === 'string'
+      return isString ? selectedOption : selectedOption[this.textBy]
+    },
+    selectedOption () {
+      return (!this.valueProxy || this.multiple) ? null : this.options.find(option => this.compareOptions(option, this.valueProxy)) || null
+    },
+    filteredOptions () {
+      if (!this.search) {
+        return this.options
+      }
+
+      return this.options.filter(option => {
+        const optionText = this.getText(option).toUpperCase()
+        const search = this.search.toUpperCase()
+        return optionText.includes(search)
+      })
+    },
+    showClearIcon () {
+      if (this.noClear) {
+        return false
+      }
+      if (this.disabled) {
+        return false
+      }
+      return this.multiple ? this.valueProxy.length : this.valueProxy !== this.clearValue
+    },
+    inputWrapperStyles () {
+      let paddingRight = 2
+      if (this.showClearIcon) {
+        paddingRight += 2
+      }
+      return {
+        paddingRight: `${paddingRight}rem`,
+        paddingTop: this.label ? this.multiple ? '.59rem' : '.84rem' : 'inherit',
+        paddingBottom: this.label ? 0 : this.multiple ? '.3125rem' : '.4375rem',
+      }
+    },
+    valueProxy: {
+      get () {
+        return this.value
+      },
+      set (value) {
+        this.$emit('input', value)
+      },
+    },
+  },
+  methods: {
+    getOptionClass (option) {
+      return {
+        'va-select__option': true,
+        'va-select__option--selected': this.isSelected(option),
+      }
+    },
+    getOptionStyle (option) {
+      return {
+        color: this.isSelected(option) ? this.$themes['success'] : 'inherit',
+        backgroundColor: this.isHovered(option) ? getHoverColor(this.$themes['success']) : 'transparent',
+      }
+    },
+    getText (option) {
+      return typeof option === 'string' ? option : option[this.textBy]
+    },
+    getKey (option) {
+      return typeof option === 'string' ? option : option[this.keyBy]
+    },
+    updateSearch (val) {
+      this.search = val
+    },
+    compareOptions (one, two) {
+      // identity check works nice for strings and exact matches.
+      if (one === two) {
+        return true
+      }
+      if (typeof this.value === 'string') {
+        return false
+      }
+      return one[this.keyBy] === two[this.keyBy]
+    },
+    isSelected (option) {
+      if (typeof option === 'string') {
+        return this.multiple
+          ? this.valueProxy.includes(option)
+          : this.valueProxy === option
+      } else {
+        return this.multiple
+          ? this.valueProxy.filter(item => item[this.keyBy] === option[this.keyBy]).length
+          : this.valueProxy[this.keyBy] === option[this.keyBy]
+      }
+    },
+    isHovered (option) {
+      return this.hoveredOption
+        ? typeof option === 'string' ? option === this.hoveredOption : this.hoveredOption[this.keyBy] === option[this.keyBy]
+        : false
+    },
+    selectOption (option) {
+      this.search = ''
+      const isSelected = this.isSelected(option)
+      const value = this.value || []
+
+      if (this.multiple) {
+        this.valueProxy = isSelected
+          ? value.filter(optionSelected => option !== optionSelected)
+          : [...value, option]
+        this.$refs.dropdown.updatePopper()
+      } else {
+        this.valueProxy = typeof option === 'string' ? option : { ...option }
+        this.search = ''
+        this.$refs.dropdown.hide()
+      }
+      if (this.searchable) {
+        this.$refs.search.$refs.input.focus()
+      }
+    },
+    clear () {
+      this.valueProxy = this.multiple
+        ? (Array.isArray(this.clearValue) ? this.clearValue : [])
+        : this.clearValue
+      this.search = ''
+    },
+    updateHoveredOption (option) {
+      if (option) {
+        this.hoveredOption = typeof option === 'string' ? option : { ...option }
+      } else {
+        this.hoveredOption = null
+      }
+    },
+  },
+  mounted () {
+    this.mounted = true
+  },
+}
+</script>
+
+<style lang="scss">
+@import "../../vuestic-sass/resources/resources";
+
+.va-select {
+  cursor: pointer;
+  display: flex;
+  align-items: flex-end;
+  position: relative;
+  width: 100%;
+  min-height: 2.375rem;
+  border-style: solid;
+  border-width: 0 0 thin 0;
+  border-top-left-radius: 0.5rem;
+  border-top-right-radius: 0.5rem;
+  margin-bottom: 1rem;
+
+  &--disabled {
+    @include va-disabled()
+  }
+
+  &--loading {
+    .va-select__clear-icon,
+    .va-select__open-icon {
+      visibility: hidden;
+    }
+  }
+
+  &__label {
+    @include va-title();
+    position: absolute;
+    top: .125rem;
+    left: .5rem;
+    margin-bottom: .5rem;
+    max-width: calc(100% - .25rem);
+    @include va-ellipsis();
+    transform-origin: top left;
+  }
+
+  &__input-wrapper {
+    display: flex;
+    flex-direction: column;
+    align-items: flex-start;
+    height: 100%;
+    width: 100%;
+    justify-content: stretch;
+    padding-left: .5rem;
+  }
+
+  &__input {
+    border: none;
+    background: transparent;
+    padding: 0.25rem 0;
+    font-size: 1rem;
+    font-family: $font-family-sans-serif;
+    font-weight: normal;
+    font-style: normal;
+    font-stretch: normal;
+    line-height: 1.5;
+    letter-spacing: normal;
+    white-space: nowrap;
+    text-overflow: ellipsis;
+    overflow: hidden;
+    margin: 0 .5rem;
+    &:focus {
+      outline: none;
+    }
+  }
+
+  &__displayed-text {
+    white-space: nowrap;
+    overflow-x: hidden;
+    text-overflow: ellipsis;
+    width: 100%;
+  }
+  &__placeholder {
+    opacity: .5;
+    white-space: nowrap;
+    text-overflow: ellipsis;
+    overflow: hidden;
+    width: 100%;
+  }
+
+  &__clear-icon {
+    color: $va-link-color-secondary;
+    width: 1.5rem;
+    height: 1.5rem;
+    padding: .25rem;
+    position: absolute;
+    top: 0;
+    bottom: 0;
+    right: 2rem;
+    margin: auto;
+  }
+
+  &__open-icon {
+    @extend .va-select__clear-icon;
+    right: .5rem;
+  }
+
+  &__tags {
+    & > .va-chip{
+      margin-right: .25rem;
+      &:last-of-type {
+        margin-top: .125rem;
+        margin-bottom: .125rem;
+      }
+    }
+  }
+
+  &__loading {
+    position: absolute;
+    right: .5rem;
+    top: 0;
+    bottom: 0;
+    margin: auto;
+  }
+
+  &__dropdown {
+    outline: none;
+    margin: 0;
+    padding: 0;
+    background: $light-gray3;
+    border-radius: .5rem;
+
+    &.va-select__dropdown-position-top {
+      box-shadow: 0 -2px 3px 0 rgba(98, 106, 119, 0.25);
+    }
+
+    .va-dropdown__anchor {
+      display: block;
+    }
+
+    .va-dropdown__content {
+      background-color: $light-gray3;
+      margin: 0;
+      padding: 0;
+      overflow-y: auto;
+      box-shadow: $datepicker-box-shadow;
+      border-radius: .5rem;
+    }
+  }
+
+  &__option-list {
+    width: 100%;
+    list-style: none;
+    &.no-options {
+      padding: .5rem;
+    }
+  }
+
+  &__option {
+    cursor: pointer;
+    display: flex;
+    align-items: center;
+    padding: .375rem .5rem .375rem .5rem;
+    min-height: 2.25rem;
+
+    &__selected-icon {
+      margin-left: auto;
+      font-size: 1.2rem;
+    }
+
+    &__icon {
+      margin-right: .5rem;
+    }
+  }
+}
+</style>
diff --git a/src/vuestic-theme/vuestic-components/va-select/getDemoData.js b/src/vuestic-theme/vuestic-components/va-select/getDemoData.js
new file mode 100644
index 0000000000000000000000000000000000000000..c17b3a468ecf3af7b9833c2844e883a4614b3975
--- /dev/null
+++ b/src/vuestic-theme/vuestic-components/va-select/getDemoData.js
@@ -0,0 +1,33 @@
+export const objectOptionsList = [{ id: 1, text: 'one' }, { id: 2, text: 'two' }, { id: 3, text: 'three' }]
+
+export const iconOptionsList = [
+  {
+    text: 'item1',
+    id: 0,
+    value: 0,
+    icon: 'fa fa-address-book',
+  },
+  {
+    text: 'item2',
+    id: 1,
+    value: 1,
+    icon: 'fa fa-android',
+  },
+  {
+    text: 'item2',
+    id: 2,
+    value: 2,
+    icon: 'fa fa-android',
+  },
+  {
+    text: 'item2',
+    id: 3,
+    value: 3,
+  },
+  {
+    text: 'item2',
+    id: 4,
+    value: 4,
+    icon: 'fa fa-android',
+  },
+]
diff --git a/src/vuestic-theme/vuestic-components/va-select/va-select.docs.md b/src/vuestic-theme/vuestic-components/va-select/va-select.docs.md
new file mode 100644
index 0000000000000000000000000000000000000000..0a4a194405b9b71b601f2fbfb6182fe4e0f09802
--- /dev/null
+++ b/src/vuestic-theme/vuestic-components/va-select/va-select.docs.md
@@ -0,0 +1,42 @@
+#Select
+```html
+<va-select
+  :options="options"
+  v-model="value"
+  label="Country"
+  placeholder="Select country"
+  clearable="false"
+/>
+
+<va-select
+  :options="options"
+  v-model="value"
+  multiple
+  searchable
+/>
+```
+
+**Props**
+
+* `value` - String|Array
+* `label` - String - label of select
+* `placeholder` - String - placeholder of select
+* `options` - Array (default: []) - list of select options. You can use strings or objects as an option. See the object option structure below. 
+* `position`: String (default: 'bottom') - direction of select open (one of these values: 'bottom', 'top'),
+* `multiple` - Boolean (default: false) - changes select to multiple
+* `tagMax` - Number (default: 5) - the max number of chips, when the number of selected items is bigger then max, there is only text '6 items selected'
+* `searchable` - Boolean (default: false) - if set true, input can be edited and options are filter automatically by inputted text
+* `disabled` - Boolean (default: false) - disable the select
+* `readonly` - Boolean (default: false) - puts input in readonly state 
+* `width` - String (default: 100%) - the width of the select
+* `maxHeight` - String (default: 128px) - the maximum height of the select
+* `noOptionsText` - String (default: 'Items not found') - set the custom text, if there are no options in select     
+* `fixed` - Boolean (default: true) - Fixed dropdown works fine even if container is `position: relative; overflow: hidden`
+* `error` - Boolean (default: false) - Sets error state
+* `success` - Boolean (default: false) - Sets the success state
+
+***Option***
+
+* `text` - String - displayed text of option. Field name can be changed by `text-by` prop
+* `icon` - String
+* `id` - String | Number - option key. Field name can be changed by `key-by` prop
diff --git a/src/vuestic-theme/vuestic-components/va-tabs/VaTab.vue b/src/vuestic-theme/vuestic-components/va-tabs/VaTab.vue
index 5741b8845c597561adbcf7ed275773719ab87413..c7ab65c2c6dedfa876dfdaf537b7df29d26891d3 100644
--- a/src/vuestic-theme/vuestic-components/va-tabs/VaTab.vue
+++ b/src/vuestic-theme/vuestic-components/va-tabs/VaTab.vue
@@ -1,14 +1,15 @@
 <template>
   <div
-    @click="selectTab"
     class="va-tab"
     :class="{
-    'va-tab--active': isActive(),
-    'va-tab--disabled': disabled
+      'va-tab--active': isActive,
+      'va-tab--disabled': disabled
     }"
-    :style="{width: widthComputed}"
+    @click="$emit('tabClick', !isActive)"
   >
-    <slot/>
+    <div class="va-tab__content" ref="content">
+      <slot/>
+    </div>
   </div>
 </template>
 
@@ -17,46 +18,71 @@ export default {
   name: 'va-tab',
   props: {
     disabled: {
-      type: Boolean
-    }
+      type: Boolean,
+    },
   },
-  computed: {
-    widthComputed () {
-      return this.$parent.grow ? 100 / this.$parent.$slots.default.length + '%' : ''
+  data () {
+    return {
+      isActive: false,
     }
   },
-  methods: {
-    selectTab () {
-      this.$parent.selectTab(this)
+  inject: {
+    tabGroup: {
+      default: null,
     },
-    isActive () {
-      return this.$parent.tabSelected(this)
-    }
+  },
+  created () {
+    this.tabGroup && this.tabGroup.register(this)
   },
   beforeDestroy () {
-    if (this.$parent.$children.indexOf(this) === this.$parent.value &&
-      this.$parent.value > 0) {
-      this.$parent.selectTab(this.$parent.$children[this.$parent.value - 1])
-    }
-  }
+    this.tabGroup && this.tabGroup.unregister(this)
+  },
 }
 </script>
 
 <style lang="scss">
+@import "../../vuestic-sass/resources/resources";
+
 .va-tab {
+  align-items: center;
+  display: inline-flex;
+  flex: 0 1 auto;
+  font-weight: $font-weight-bold;
+  line-height: normal;
+  height: inherit;
+  max-width: 264px;
+  text-align: center;
+  vertical-align: middle;
+
   padding: 0.4375rem 0.75rem;
-  margin-left: 0.5rem;
-  margin-right: 0.5rem;
-  opacity: 0.5;
   font-weight: $font-weight-bold;
   cursor: pointer;
-  display: flex;
-  justify-content: center;
-  &:hover, &--active {
-    opacity: 1;
+
+  &:not(.va-tab--active) {
+    opacity: .5;
+  }
+
+  &__content {
+    align-items: center;
+    color: inherit;
+    display: flex;
+    flex: 1 1 auto;
+    height: 100%;
+    justify-content: center;
+    max-width: inherit;
+    text-decoration: none;
+    transition: $transition-primary;
+    user-select: none;
+    white-space: normal;
   }
-  &--disabled {
-    cursor: default;
+
+  .va-tab--disabled {
+    .va-tab__container {
+      @include va-disabled();
+    }
+
+    pointer-events: none;
+    cursor: inherit;
   }
 }
 </style>
diff --git a/src/vuestic-theme/vuestic-components/va-tabs/VaTabs.demo.vue b/src/vuestic-theme/vuestic-components/va-tabs/VaTabs.demo.vue
index 47b2690f4460df78184a1b79ed99045b72344e87..0a00fece7126365b6aa40cd3b0133ad0514610e7 100644
--- a/src/vuestic-theme/vuestic-components/va-tabs/VaTabs.demo.vue
+++ b/src/vuestic-theme/vuestic-components/va-tabs/VaTabs.demo.vue
@@ -1,58 +1,121 @@
 <template>
   <VbDemo>
-    <VbContainer style="width: 100%">
+    <VbCard refresh title="Tabs usage example">
+      <TabsExample/>
+    </VbCard>
+    <VbCard title="Default">
+      <va-tabs v-model="tabValue">
+        <va-tab
+          v-for="title in tabTitles"
+          :key="title"
+        >
+          {{title}}
+        </va-tab>
+      </va-tabs>
+    </VbCard>
+    <VbCard title="Align right" width="400px">
+      <va-tabs right v-model="tabValue">
+        <va-tab
+          v-for="title in tabTitles"
+          :key="title"
+        >
+          {{title}}
+        </va-tab>
+      </va-tabs>
+    </VbCard>
+    <VbCard title="Centered" width="400px">
+      <va-tabs center v-model="tabValue">
+        <va-tab
+          v-for="title in tabTitles"
+          :key="title"
+        >
+          {{title}}
+        </va-tab>
+      </va-tabs>
+    </VbCard>
+    <VbCard title="Grow" width="400px">
+      <va-tabs grow v-model="tabValue">
+        <va-tab
+          v-for="title in tabTitles"
+          :key="title"
+        >
+          {{title}}
+        </va-tab>
+      </va-tabs>
+    </VbCard>
+    <VbCard title="Overflow">
       <va-tabs
-        v-model="value"
-        :right="option === 'align-right'"
-        :grow="option == 'grow'"
-        :color="color"
-        :hide-slider="hideSlider"
+        style="width: 120px"
+        v-model="tabValue"
       >
-        <va-tab>{{'item1item1item1item1item1'}}</va-tab>
-        <va-tab
-          v-for="item in count"
-          :key="item"
-        >
-          {{'item'+ item}}
-        </va-tab>
-      </va-tabs>
-      {{value}}
-    </VbContainer>
-    <VbContainer>
-      <button @click="count++">add item</button>
-      <button @click="count--">remove item</button>
-    </VbContainer>
-    <VbContainer>
-      <vuestic-radio-button
-        v-for="value in options"
-        :key="value"
-        v-model="option"
-        :option="value"
-      />
-    </VbContainer>
-    <VbContainer>
-      <vuestic-checkbox v-model="hideSlider" label="hide-slider"/>
-    </VbContainer>
+        <va-tab
+          v-for="title in tabTitles"
+          :key="title"
+        >
+          {{title}}
+        </va-tab>
+      </va-tabs>
+    </VbCard>
+    <VbCard title="Overflow text">
+      <va-tabs v-model="tabValue">
+        <va-tab
+          v-for="title in tabTitles"
+          :key="title"
+        >
+          {{title}}
+        </va-tab>
+        <va-tab>
+          Somewhat long long long long long long long long text
+        </va-tab>
+      </va-tabs>
+    </VbCard>
+    <VbCard title="Overflow text + grow">
+      <va-tabs grow v-model="tabValue">
+        <va-tab
+          v-for="title in tabTitles"
+          :key="title"
+        >
+          {{title}}
+        </va-tab>
+        <va-tab>
+          Somewhat long long long long long long long long long text
+        </va-tab>
+      </va-tabs>
+    </VbCard>
+    <VbCard title="Hide slider">
+      <va-tabs hideSlider v-model="tabValue">
+        <va-tab
+          v-for="title in tabTitles"
+          :key="title"
+        >
+          {{title}}
+        </va-tab>
+      </va-tabs>
+    </VbCard>
   </VbDemo>
 </template>
 
 <script>
-import VuesticCheckbox from '../va-checkbox/VaCheckbox'
-import VuesticRadioButton from '../vuestic-radio-button/VuesticRadioButton'
+import VaCheckbox from '../va-checkbox/VaCheckbox'
+import VaRadioButton from '../va-radio-button/VaRadioButton'
+import VaAdvancedColorPicker from '../va-color-picker/VaAdvancedColorPicker'
+import VaTabs from './VaTabs'
+import VaTab from './VaTab'
+import TabsExample from './__demo__/TabsExample'
 
 export default {
   components: {
-    VuesticRadioButton,
-    VuesticCheckbox,
+    TabsExample,
+    VaAdvancedColorPicker,
+    VaRadioButton,
+    VaCheckbox,
+    VaTabs,
+    VaTab,
   },
   data () {
     return {
-      count: 6,
-      value: 4,
-      options: ['default', 'align-right', 'grow'],
-      option: 'default',
-      color: 'White',
-      hideSlider: false,
+      tabTitles: ['One', 'Two', 'Three'],
+      tabValue: 1,
     }
   },
 }
diff --git a/src/vuestic-theme/vuestic-components/va-tabs/VaTabs.vue b/src/vuestic-theme/vuestic-components/va-tabs/VaTabs.vue
index c028f6ac38c23d5fd9ae87e13f42a8d3243920c1..6341fc08ffc62aec74a106d21d08eb7826fd376c 100644
--- a/src/vuestic-theme/vuestic-components/va-tabs/VaTabs.vue
+++ b/src/vuestic-theme/vuestic-components/va-tabs/VaTabs.vue
@@ -1,54 +1,65 @@
 <template>
   <div class="va-tabs">
-    <div
-      class="va-tabs__bar va-row"
-      :class="{
-       'va-tabs__bar--align-right': right,
-       'va-tabs__bar--grow': grow
-      }"
-    >
+    <div class="va-tabs__wrapper">
       <div
-        class="va-tabs__bar-content"
-        :class="{'va-tabs__bar-content--grow': grow}"
+        class="va-tabs__container"
+        :class="containerClass"
       >
-        <div
-          class="va-tabs__bar-content-items"
-          :class="{'grow': grow}"
-        >
-          <slot/>
-        </div>
-        <div
-          v-if="!hideSlider"
-          class="va-tabs__bar-content-slider"
-          :style="{
-             width: getBarWidth($slots.default),
-             marginLeft: getMarginLeft($slots.default)
-          }"
-        >
-          <div class="va-tabs__bar-content-slider-line"/>
+        <div class="va-tabs__slider-wrapper" :style="sliderStyles">
+          <div class="va-tabs__slider"/>
         </div>
+        <slot/>
       </div>
     </div>
   </div>
 </template>
 
 <script>
+
+import VaTab from './VaTab'
+
 export default {
   name: 'va-tabs',
-  props: {
-    value: {
-      required: true
-    },
-    right: {
-      type: Boolean
-    },
-    grow: {
-      type: Boolean
-    },
-    hideSlider: {
-      type: Boolean
+  components: {
+    VaTab,
+  },
+  provide () {
+    return {
+      tabGroup: {
+        register: this.register,
+        unregister: this.unregister,
+      },
+    }
+  },
+  data () {
+    return {
+      tabs: [],
+      tabsWidth: [],
+      sliderLeft: 0,
+      sliderWidth: 0,
     }
   },
+  subs: {
+    resizeEnd () {
+      this.updateSlider()
+    },
+  },
+  props: {
+    value: { type: Number },
+    right: Boolean,
+    center: Boolean,
+    grow: Boolean,
+    hideSlider: Boolean,
+  },
+  mounted () {
+    this.updateSlider()
+  },
+  watch: {
+    value: 'syncStateWithValue',
+    right: 'updateSlider',
+    grow: 'updateSlider',
+    hideSlider: 'updateSlider',
+  },
   computed: {
     valueProxy: {
       set (valueProxy) {
@@ -56,108 +67,133 @@ export default {
       },
       get () {
         return this.value
+      },
+    },
+    containerClass () {
+      return {
+        'va-tabs__container--grow': this.grow,
+        'va-tabs__container--right': this.right,
+        'va-tabs__container--center': this.center,
       }
-    }
+    },
+    sliderStyles () {
+      return this.selectedTab
+        ? {
+          left: `${this.sliderLeft}px`,
+          width: `${this.sliderWidth}px`,
+        }
+        : {}
+    },
+    selectedTab () {
+      return this.tabs[this.value] || null
+    },
   },
   methods: {
-    setTabsWidth (slots) {
-      let count = 0
-      slots.forEach(vnode => {
-        if (vnode.elm) {
-          this.tabsWidth[count] = vnode.elm.clientWidth
-          count++
-        }
+    syncStateWithValue () {
+      this.tabs.forEach((tab, index) => {
+        tab.isActive = index === this.value
       })
+      this.updateSlider()
     },
-    getBarWidth (slots) {
-      this.setTabsWidth(slots)
-      return this.grow ? 100 / slots.length + '%' : `calc(` + this.tabsWidth[this.value] + `px - 1.25rem)`
-    },
-    getMarginLeft (slots) {
-      this.setTabsWidth(slots)
-      if (!this.grow && this.value === 0) {
-        return 1.25 + 'rem'
+    register (tab) {
+      const index = this.tabs.push(tab) - 1
+      tab.$on('tabClick', () => this.onTabClick(tab))
+
+      if (index === this.value) {
+        tab.isActive = true
       }
-      if (!this.grow && this.value !== 0) {
-        let marginLeft = 0
-        for (let count = 0; count < this.value; count++) {
-          marginLeft += this.tabsWidth[count]
-        }
-        return `calc(` + marginLeft + `px + ` + this.value + `rem + 1.2rem)`
+    },
+    unregister (tab) {
+      if (this._isDestroyed) return
+
+      this.tabs.splice(this.tabs.indexOf(tab), 1)
+
+      this.syncStateWithValue()
+    },
+    onTabClick (tab) {
+      const index = this.tabs.indexOf(tab)
+      this.valueProxy = index
+    },
+    async updateSlider () {
+      await this.$nextTick()
+
+      if (this.hideSlider) {
+        return
       }
-      if (this.grow && this.value !== 0) {
-        return this.value * (100 / slots.length) + `%`
+      const selectedTab = this.selectedTab
+      if (!selectedTab || !selectedTab.$refs.content) {
+        return
       }
+      const content = selectedTab.$refs.content
+      this.sliderWidth = content.scrollWidth + 4
+      this.sliderLeft = content.offsetLeft - 2
     },
-    selectTab (tabToSelect) {
-      this.$slots.default.forEach((tabSlot, index) => {
-        if (tabSlot.componentInstance === tabToSelect) {
-          this.valueProxy = index
-        }
-      })
-    },
-    tabSelected (tabToCompare) {
-      return this.$slots.default.some((tabSlot, index) => {
-        if (tabSlot.componentInstance === tabToCompare) {
-          return index === this.value
-        }
-      })
-    }
-  },
-  data () {
-    return {
-      tabsWidth: []
-    }
   },
-  mounted () {
-    let count = 0
-    this.$slots.default.forEach(vnode => {
-      if (vnode.elm.clientWidth) {
-        this.tabsWidth[count] = vnode.elm.clientWidth
-        count++
-      }
-    })
-  }
 }
 </script>
 
 <style lang="scss">
+@import "../../vuestic-sass/resources/resources";
+
 .va-tabs {
-  &__bar {
-    padding-top: 1rem;
-    &--align-right {
-      justify-content: flex-end;
-    }
+  position: relative;
+
+  &--right {
+    display: flex;
+    justify-content: flex-end;
+  }
+
+  .va-tabs__wrapper {
+    overflow: auto;
+    contain: content;
+    display: flex;
+  }
+
+  .va-tabs__container {
+    flex: 1 0 auto;
+    display: flex;
+    height: calc(2.5rem + 18px);
+    list-style-type: none;
+    transition: transform 0.6s cubic-bezier(0.86, 0, 0.07, 1);
+    white-space: nowrap;
+    position: relative;
+
     &--grow {
-      justify-content: space-around;
+      .va-tab {
+        flex: 1 0 auto;
+        max-width: none;
+      }
     }
-    &-content {
-      margin-bottom: 2.5rem;
-      &--grow {
-        width: 100%;
+
+    &--center, &--right {
+      > .va-tab:first-child {
+        margin-left: auto
       }
-      &-items {
-        display: flex;
-        &.grow {
-          justify-content: space-around;
-        }
+
+      .va-tabs__slider-wrapper + .va-tab {
+        margin-left: auto;
       }
-      &-slider {
-        display: flex;
-        transition: margin-left 0.3s;
-        &.align-right {
-          justify-content: flex-end;
-        }
-        &.grow {
-          justify-content: space-around;
-        }
-        &-line {
-          width: 100%;
-          height: 2px;
-          background-color: $vue-green;
-        }
+    }
+
+    &--center {
+      > .va-tab:last-child {
+        margin-right: auto;
       }
     }
   }
+
+  .va-tabs__slider-wrapper {
+    bottom: 0;
+    margin: 0 !important;
+    position: absolute;
+    z-index: 4000;
+    transition: $transition-primary;
+
+    .va-tabs__slider {
+      width: 100%;
+      height: 0.125rem;
+      background-color: $brand-primary;
+    }
+  }
 }
 </style>
diff --git a/src/vuestic-theme/vuestic-components/va-tabs/VuesticTabs.vue b/src/vuestic-theme/vuestic-components/va-tabs/VuesticTabs.vue
deleted file mode 100644
index 5c932ae6e3947fb30adf5c22cfeac5f828ee0aae..0000000000000000000000000000000000000000
--- a/src/vuestic-theme/vuestic-components/va-tabs/VuesticTabs.vue
+++ /dev/null
@@ -1,122 +0,0 @@
-<template>
-  <div class="vuestic-tabs">
-    <div>
-      <nav class="nav nav-pills va-row">
-        <div
-          class="nav-item col"
-          @click="setActive(name)"
-          :class="{active: name === currentActive}"
-          v-for="name in names"
-          :key="name"
-        >
-          <span class="nav-link"><h5>{{name}}</h5></span>
-        </div>
-      </nav>
-      <div class="track">
-        <div :class="underscoreClass"></div>
-      </div>
-    </div>
-    <vuestic-simple-select
-      class="simple-select"
-      v-show="false"
-      v-bind:options="names" v-model="currentActive"></vuestic-simple-select>
-    <div class="tab-content">
-      <div
-        class="tab-pane"
-        :class="{active: name === currentActive}"
-        v-for="name in names"
-        :key="name"
-      >
-        <slot :name="name"></slot>
-      </div>
-    </div>
-  </div>
-</template>
-
-<script>
-// d-none and d-lg-flex were deleted, bug will be fixed in the nearest update
-export default {
-  name: 'vuestic-tabs',
-  props: ['names'],
-  computed: {
-    underscoreClass () {
-      return 'underscore-' + this.names.length + '-' + this.names.indexOf(this.currentActive)
-    },
-  },
-  methods: {
-    setActive (name) {
-      this.currentActive = name
-    },
-  },
-  data () {
-    return {
-      currentActive: this.names[0],
-    }
-  },
-}
-</script>
-
-<style lang="scss">
-.vuestic-tabs {
-  background-color: white;
-  .simple-select {
-    padding-top: 1.5rem;
-  }
-  .nav {
-    margin: 0;
-    padding-top: 2.25rem;
-    .nav-item {
-      flex-grow: 1;
-      text-align: center;
-      padding: 0;
-      .nav-link {
-        padding: 0;
-        color: $gray;
-        transition: all .3s ease;
-      }
-      &:hover {
-        cursor: pointer;
-        .nav-link {
-          color: $vue-darkest-blue;
-        }
-      }
-      &.active {
-        .nav-link {
-          color: $vue-darkest-blue;
-        }
-      }
-    }
-  }
-  .track {
-    overflow: hidden;
-    width: 100%;
-    height: .125rem;
-    position: relative;
-    div[class^='underscore-'] {
-      background-color: $brand-primary;
-      height: .125rem;
-      position: absolute;
-    }
-    $koeff: 0.8;
-    @for $all from 1 through 10 {
-      $width: 1/$all;
-      div[class^='underscore-#{$all}'] {
-        width: $width * $koeff * 100%;
-        transition: left .5s cubic-bezier(0.68, -0.55, 0.265, 1.55);
-      }
-      @for $place from 0 through $all {
-        .underscore-#{$all}-#{$place} {
-          left: ($place + (1 - $koeff)/2) * $width * 100%;
-        }
-      }
-    }
-  }
-  .tab-content {
-    padding-bottom: $tab-content-pb;
-    padding-top: $tab-content-pt;
-    > .tab-pane {
-      width: 100%
-    }
-  }
-}
-</style>
diff --git a/src/vuestic-theme/vuestic-components/va-tabs/__demo__/TabsExample.vue b/src/vuestic-theme/vuestic-components/va-tabs/__demo__/TabsExample.vue
new file mode 100644
index 0000000000000000000000000000000000000000..adce66d87fc96da6d19a0a6c3d9f7915589c9214
--- /dev/null
+++ b/src/vuestic-theme/vuestic-components/va-tabs/__demo__/TabsExample.vue
@@ -0,0 +1,70 @@
+<template>
+  <div>
+    <va-tabs v-model="selectedTabIndex">
+      <va-tab
+        v-for="tabObject in tabObjects"
+        :key="tabObject.key"
+      >
+        {{ tabObject.title }}
+        <va-icon
+          icon="fa fa-times"
+          class="ml-2"
+          @click.stop.native="removeTab(tabObject)"
+        />
+      </va-tab>
+    </va-tabs>
+
+    <div style="height: 20px"/>
+
+    <div>
+      Content: {{ selectedTab ? selectedTab.title : 'none' }}
+    </div>
+    <div>
+      <input type="number" v-model.number="selectedTabIndex">
+    </div>
+  </div>
+</template>
+
+<script>
+import VaTabs from '../VaTabs'
+import VaTab from '../VaTab'
+import VaIcon from '../../va-icon/VaIcon'
+
+export default {
+  name: 'TabsExample',
+  components: {
+    VaIcon,
+    VaTab,
+    VaTabs,
+  },
+  data () {
+    return {
+      selectedTabIndex: 0,
+      tabObjects: [
+        {
+          key: 'products',
+          title: 'Products',
+        },
+        {
+          key: 'orders',
+          title: 'Orders',
+        },
+        {
+          key: 'cart',
+          title: 'Cart',
+        },
+      ],
+    }
+  },
+  computed: {
+    selectedTab () {
+      return this.tabObjects[this.selectedTabIndex]
+    },
+  },
+  methods: {
+    removeTab (tabToRemove) {
+      this.tabObjects = this.tabObjects.filter(tab => tab !== tabToRemove)
+    },
+  },
+}
+</script>
diff --git a/src/vuestic-theme/vuestic-components/va-tabs/tabs-docs.md b/src/vuestic-theme/vuestic-components/va-tabs/tabs-docs.md
new file mode 100644
index 0000000000000000000000000000000000000000..c0e98e4e2edc80499e062d640bbddc5ba974edf6
--- /dev/null
+++ b/src/vuestic-theme/vuestic-components/va-tabs/tabs-docs.md
@@ -0,0 +1,35 @@
+### Limitations
+
+For now we focus on bare-bones tabs and make them solid.
+
+* Only one style option.
+* There is no content, only tabs themselves.
+* Tabs are positioned only on top.
+* Scroll is native scroll. No fancy arrows or custom scroll.
+
+### Template
+
+```html
+<va-tabs v-model="tabValue">
+  <va-tab
+    v-for="title in tabTitles"
+    :key="title"
+  >
+    {{title}}
+  </va-tab>
+</va-tabs>
+```
+
+### Props
+
+#### Component: va-tabs
+
+* `value` - Number  - selected tab index.
+* `right` - Boolean - align right.
+* `center` - Boolean - align center.
+* `grow` - Boolean - tabs will take full width.
+* `hideSlider` - Boolean - hide slider.
+
+#### Component: va-tab
+
+Has no props.
diff --git a/src/vuestic-theme/vuestic-components/vuestic-chart/VuesticChart.demo.vue b/src/vuestic-theme/vuestic-components/vuestic-chart/VuesticChart.demo.vue
deleted file mode 100644
index 323ce55371584cff529da33031d27f14613d2c16..0000000000000000000000000000000000000000
--- a/src/vuestic-theme/vuestic-components/vuestic-chart/VuesticChart.demo.vue
+++ /dev/null
@@ -1,45 +0,0 @@
-<template>
-  <div class="demo-container">
-    <div class="demo-container__item">
-      <vuestic-simple-select
-        :options="chartTypes"
-        v-model="chartType"
-      />
-      <va-button @click="refreshData()">
-        refreshData
-      </va-button>
-
-      <vuestic-chart :data="chartData" :type="chartType"/>
-    </div>
-  </div>
-</template>
-
-<script>
-import VuesticChart from './VuesticChart.vue'
-import VuesticSimpleSelect from '../vuestic-simple-select/VuesticSimpleSelect'
-// TODO Demo is non operational
-// HACK Data is bound to vuex
-// import { chartTypes } from './VuesticChartConfigs'
-// import { getLineChartData } from '../../../data/charts/LineChartData'
-
-export default {
-  data () {
-    return {
-      // chartData: getLineChartData(),
-      chartType: 'pie',
-    }
-  },
-  components: {
-    VuesticSimpleSelect,
-    VuesticChart,
-  },
-  computed: {
-    // chartTypes: () => chartTypes,
-  },
-  methods: {
-    refreshData () {
-      // this.chartData = getLineChartData()
-    },
-  },
-}
-</script>
diff --git a/src/vuestic-theme/vuestic-components/vuestic-chart/VuesticChart.vue b/src/vuestic-theme/vuestic-components/vuestic-chart/VuesticChart.vue
deleted file mode 100644
index 7991cc25328dfdcae0dd7d40d794d6127bc2655c..0000000000000000000000000000000000000000
--- a/src/vuestic-theme/vuestic-components/vuestic-chart/VuesticChart.vue
+++ /dev/null
@@ -1,72 +0,0 @@
-<template>
-  <component
-    ref="chart"
-    class='vuestic-chart'
-    :is="chartComponent"
-    :options="options"
-    :chart-data="data"
-  />
-</template>
-
-<script>
-import PieChart from './chart-types/PieChart'
-import BubbleChart from './chart-types/BubbleChart'
-import DonutChart from './chart-types/DonutChart'
-import HorizontalBarChart from './chart-types/HorizontalBarChart'
-import VerticalBarChart from './chart-types/VerticalBarChart'
-import LineChart from './chart-types/LineChart'
-import { chartTypesMap } from './VuesticChartConfigs'
-
-export default {
-  name: 'vuestic-chart',
-  props: {
-    data: {},
-    options: {},
-    type: {
-      validator (type) {
-        const valid = type in chartTypesMap
-
-        if (!valid) {
-          // eslint-disable-next-line no-console
-          console.warn(`There is no chart of ${type} type`)
-        }
-
-        return valid
-      },
-    },
-  },
-  components: {
-    PieChart,
-    LineChart,
-    VerticalBarChart,
-    HorizontalBarChart,
-    DonutChart,
-    BubbleChart,
-  },
-  computed: {
-    chartComponent () {
-      return chartTypesMap[this.type]
-    },
-  },
-}
-</script>
-
-<style lang='scss'>
-.vuestic-chart {
-  width: 100%;
-  height: 100%;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-
-  > * {
-    height: 100%;
-    width: 100%;
-  }
-
-  canvas {
-    width: 100%;
-    height: auto;
-  }
-}
-</style>
diff --git a/src/vuestic-theme/vuestic-components/vuestic-chart/VuesticChartConfigs.js b/src/vuestic-theme/vuestic-components/vuestic-chart/VuesticChartConfigs.js
deleted file mode 100644
index 17fce37e5db4a7b0f26b469848aa14d1a0709ee7..0000000000000000000000000000000000000000
--- a/src/vuestic-theme/vuestic-components/vuestic-chart/VuesticChartConfigs.js
+++ /dev/null
@@ -1,29 +0,0 @@
-export const defaultConfig = {
-  legend: {
-    position: 'bottom',
-    labels: {
-      fontColor: '#34495e',
-      fontFamily: 'sans-serif',
-      fontSize: 14,
-      padding: 20,
-      usePointStyle: true,
-    },
-  },
-  tooltips: {
-    bodyFontSize: 14,
-    bodyFontFamily: 'sans-serif',
-  },
-  responsive: true,
-  maintainAspectRatio: false,
-}
-
-export const chartTypesMap = {
-  pie: 'pie-chart',
-  donut: 'donut-chart',
-  bubble: 'bubble-chart',
-  line: 'line-chart',
-  'horizontal-bar': 'horizontal-bar-chart',
-  'vertical-bar': 'vertical-bar-chart',
-}
-
-export const chartTypes = Object.keys(chartTypesMap)
diff --git a/src/vuestic-theme/vuestic-components/vuestic-chart/chart-types/BubbleChart.js b/src/vuestic-theme/vuestic-components/vuestic-chart/chart-types/BubbleChart.js
deleted file mode 100644
index 4ff55921eea264b09e63e277793e7510fe12a5f1..0000000000000000000000000000000000000000
--- a/src/vuestic-theme/vuestic-components/vuestic-chart/chart-types/BubbleChart.js
+++ /dev/null
@@ -1,7 +0,0 @@
-import { Bubble } from 'vue-chartjs'
-import { chartMixin } from './chartMixin'
-
-export default {
-  extends: Bubble,
-  mixins: [chartMixin],
-}
diff --git a/src/vuestic-theme/vuestic-components/vuestic-chart/chart-types/DonutChart.js b/src/vuestic-theme/vuestic-components/vuestic-chart/chart-types/DonutChart.js
deleted file mode 100644
index 2478866a6f93fdd071ab73391f11d0b331be5f49..0000000000000000000000000000000000000000
--- a/src/vuestic-theme/vuestic-components/vuestic-chart/chart-types/DonutChart.js
+++ /dev/null
@@ -1,7 +0,0 @@
-import { Doughnut } from 'vue-chartjs'
-import { chartMixin } from './chartMixin'
-
-export default {
-  extends: Doughnut,
-  mixins: [chartMixin],
-}
diff --git a/src/vuestic-theme/vuestic-components/vuestic-chart/chart-types/HorizontalBarChart.js b/src/vuestic-theme/vuestic-components/vuestic-chart/chart-types/HorizontalBarChart.js
deleted file mode 100644
index 8d51ee4ac46b1e5669af89f965b2ea46fc33db7e..0000000000000000000000000000000000000000
--- a/src/vuestic-theme/vuestic-components/vuestic-chart/chart-types/HorizontalBarChart.js
+++ /dev/null
@@ -1,7 +0,0 @@
-import { HorizontalBar } from 'vue-chartjs'
-import { chartMixin } from './chartMixin'
-
-export default {
-  extends: HorizontalBar,
-  mixins: [chartMixin],
-}
diff --git a/src/vuestic-theme/vuestic-components/vuestic-chart/chart-types/LineChart.js b/src/vuestic-theme/vuestic-components/vuestic-chart/chart-types/LineChart.js
deleted file mode 100644
index 92b1bfbba6aafe21006161c81b1411140e4ab19c..0000000000000000000000000000000000000000
--- a/src/vuestic-theme/vuestic-components/vuestic-chart/chart-types/LineChart.js
+++ /dev/null
@@ -1,7 +0,0 @@
-import { Line } from 'vue-chartjs'
-import { chartMixin } from './chartMixin'
-
-export default {
-  extends: Line,
-  mixins: [chartMixin],
-}
diff --git a/src/vuestic-theme/vuestic-components/vuestic-chart/chart-types/PieChart.js b/src/vuestic-theme/vuestic-components/vuestic-chart/chart-types/PieChart.js
deleted file mode 100644
index c7330b7c2237dd9709920e6c227727852a50c264..0000000000000000000000000000000000000000
--- a/src/vuestic-theme/vuestic-components/vuestic-chart/chart-types/PieChart.js
+++ /dev/null
@@ -1,7 +0,0 @@
-import { Pie } from 'vue-chartjs'
-import { chartMixin } from './chartMixin'
-
-export default {
-  extends: Pie,
-  mixins: [chartMixin],
-}
diff --git a/src/vuestic-theme/vuestic-components/vuestic-chart/chart-types/VerticalBarChart.js b/src/vuestic-theme/vuestic-components/vuestic-chart/chart-types/VerticalBarChart.js
deleted file mode 100644
index 3fc090423ce54330f89b40b7b3ca708798c064b0..0000000000000000000000000000000000000000
--- a/src/vuestic-theme/vuestic-components/vuestic-chart/chart-types/VerticalBarChart.js
+++ /dev/null
@@ -1,7 +0,0 @@
-import { Bar } from 'vue-chartjs'
-import { chartMixin } from './chartMixin'
-
-export default {
-  extends: Bar,
-  mixins: [chartMixin],
-}
diff --git a/src/vuestic-theme/vuestic-components/vuestic-chart/chart-types/chartMixin.js b/src/vuestic-theme/vuestic-components/vuestic-chart/chart-types/chartMixin.js
deleted file mode 100644
index 10f8b3094155fef0af43341ece0068914cac284f..0000000000000000000000000000000000000000
--- a/src/vuestic-theme/vuestic-components/vuestic-chart/chart-types/chartMixin.js
+++ /dev/null
@@ -1,21 +0,0 @@
-import { mixins } from 'vue-chartjs'
-import { defaultConfig } from '../VuesticChartConfigs'
-
-export const chartMixin = {
-  mixins: [mixins.reactiveProp],
-  props: ['data', 'chartOptions'],
-  mounted () {
-    this.refresh()
-  },
-  methods: {
-    refresh () {
-      this.renderChart(this.chartData, this.options)
-    },
-  },
-  computed: {
-    // `this.options` is used by vue-chartjs mixin on refresh.
-    options () {
-      return Object.assign({}, defaultConfig, this.chartOptions)
-    },
-  },
-}
diff --git a/src/vuestic-theme/vuestic-components/vuestic-chat/VuesticChat.vue b/src/vuestic-theme/vuestic-components/vuestic-chat/VuesticChat.vue
deleted file mode 100644
index e7899416bcf87ccb11283c74d395b8b9d28ae793..0000000000000000000000000000000000000000
--- a/src/vuestic-theme/vuestic-components/vuestic-chat/VuesticChat.vue
+++ /dev/null
@@ -1,125 +0,0 @@
-<template>
-  <div class="vuestic-chat">
-    <div class="chat-body" :style="{'height': height}"
-         v-sticky-scroll="{animate: true, duration: 500}">
-      <div
-        class="chat-message"
-        v-for="(message, index) in value"
-        :key="index"
-        :class="{'yours': message.yours, 'alien': !message.yours}"
-      >
-        {{message.text}}
-      </div>
-    </div>
-    <div class="chat-controls">
-      <fieldset>
-        <div class="form-group form-group-w-btn">
-          <div class="input-group">
-            <input @keypress="keyHandler($event)" v-model="inputMessage"
-                   required title=""/>
-            <label class="control-label">Your message</label><va-icon icon="bar"/>
-          </div>
-          <va-button @click="sendMessage()">
-            Send
-          </va-button>
-        </div>
-      </fieldset>
-    </div>
-  </div>
-</template>
-
-<script>
-import StickyScroll from 'vuestic-directives/StickyScroll'
-
-export default {
-  name: 'vuestic-chat',
-  directives: { StickyScroll },
-  props: {
-    value: {
-      type: Array,
-      default: () => [],
-    },
-    height: {
-      default: '20rem',
-    },
-  },
-
-  data () {
-    return {
-      inputMessage: '',
-    }
-  },
-
-  methods: {
-    keyHandler (event) {
-      if (event.keyCode === 13) {
-        this.sendMessage()
-      }
-    },
-
-    sendMessage () {
-      if (this.inputMessage) {
-        this.$emit('input', this.value.concat({
-          text: this.inputMessage,
-          yours: true,
-        }))
-        this.inputMessage = ''
-      }
-    },
-  },
-
-  mounted () {
-    this.$emit('input', this.value)
-  },
-}
-</script>
-
-<style lang='scss' scoped>
-$chat-body-min-height: 18.75rem;
-$chat-body-mb: 1.5rem;
-$chat-message-mb: 0.625rem;
-$chat-message-py: 0.657rem;
-$chat-message-px: 1.375rem;
-$chat-message-br: 0.875rem;
-
-.vuestic-chat {
-  width: 100%;
-}
-
-.chat-body {
-  min-height: $chat-body-min-height;
-  display: flex;
-  flex-direction: column;
-  margin-bottom: $chat-body-mb;
-  overflow: auto;
-}
-
-.chat-message {
-  padding: $chat-message-py $chat-message-px;
-  margin-bottom: $chat-message-mb;
-  border-radius: $chat-message-br;
-  max-width: 70%;
-  overflow-wrap: break-word;
-
-  &:last-child {
-    margin-bottom: 0;
-  }
-
-  &.alien {
-    align-self: flex-start;
-    border-top-left-radius: 0;
-    background-color: $light-gray2;
-  }
-
-  &.yours {
-    align-self: flex-end;
-    border-top-right-radius: 0;
-    background-color: $brand-primary;
-  }
-
-  .chat-message-input {
-    resize: vertical !important;
-  }
-}
-
-</style>
diff --git a/src/vuestic-theme/vuestic-components/vuestic-grid/Spacing.demo.vue b/src/vuestic-theme/vuestic-components/vuestic-grid/Spacing.demo.vue
deleted file mode 100644
index 74add06bba56dd2647ca74309365b7129b2d2995..0000000000000000000000000000000000000000
--- a/src/vuestic-theme/vuestic-components/vuestic-grid/Spacing.demo.vue
+++ /dev/null
@@ -1,15 +0,0 @@
-<template>
-  <div class="demo-container">
-    <div class="demo-container__item">
-      <SpacingPlaygroud/>
-    </div>
-  </div>
-</template>
-
-<script>
-import SpacingPlaygroud from './SpacingPlaygroud'
-
-export default {
-  components: { SpacingPlaygroud },
-}
-</script>
diff --git a/src/vuestic-theme/vuestic-components/vuestic-grid/SpacingPlaygroud.vue b/src/vuestic-theme/vuestic-components/vuestic-grid/SpacingPlaygroud.vue
deleted file mode 100644
index 1da7ea6cedca60d0168861ad2626cb6b14ef7586..0000000000000000000000000000000000000000
--- a/src/vuestic-theme/vuestic-components/vuestic-grid/SpacingPlaygroud.vue
+++ /dev/null
@@ -1,90 +0,0 @@
-<template>
-  <div class="spacing-playground va-layout gutter--md">
-    <div class="va-row">
-      <h3>Spacing playground</h3>
-    </div>
-    <div class="va-row">
-      <div class="flex xs3">
-        <span>m</span><vuestic-simple-select :options="directionList" v-model="selectedMarginDirection"/>
-      </div>
-      <div class="flex xs2">
-        <span>-</span><vuestic-simple-select :options="sizesList" v-model="selectedMarginSize"/>
-      </div>
-      <div class="flex xs3 offset-2">
-        <span>p</span><vuestic-simple-select :options="directionList" v-model="selectedPaddingDirection"/>
-      </div>
-      <div class="flex xs2">
-        <span>-</span><vuestic-simple-select :options="sizesList" v-model="selectedPaddingSize"/>
-      </div>
-    </div>
-    <div class="va-row">
-      <div class="flex xs6">{{selectedMarginClass}}</div>
-      <div class="flex xs6">{{selectedPaddingClass}}</div>
-    </div>
-    <div class="va-row">
-      <div class="flex xs12">
-        <div class="playground-component">
-          <div class="playground-component__margin" :class="selectedMarginClass">
-            <div :class="selectedPaddingClass" class="playground-component__padding">
-              <div class="playground-component__inner"></div>
-            </div>
-          </div>
-        </div>
-      </div>
-    </div>
-    <div class="va-row">
-      <div class="flex xs12">
-        <vuestic-color-presentation color="#c9f7db" name="padding"/>
-        <vuestic-color-presentation color="#ffd093" name="margin"/>
-      </div>
-    </div>
-  </div>
-</template>
-
-<script>
-import VuesticSimpleSelect from '../vuestic-simple-select/VuesticSimpleSelect'
-import VuesticColorPresentation from '../vuestic-color-presentation/VuesticColorPresentation'
-
-export default {
-  name: 'spacing-playgroud',
-  components: { VuesticColorPresentation, VuesticSimpleSelect },
-  data () {
-    return {
-      directionList: ['a', 'y', 'x', 't', 'r', 'b', 'l'],
-      selectedMarginDirection: '',
-      selectedPaddingDirection: '',
-      sizesList: ['1', '2', '3', '4', '5', 'auto'],
-      selectedMarginSize: '',
-      selectedPaddingSize: '',
-    }
-  },
-  computed: {
-    selectedMarginClass () {
-      return (this.selectedMarginDirection && this.selectedMarginSize)
-        ? `m${this.selectedMarginDirection}-${this.selectedMarginSize}`
-        : ''
-    },
-    selectedPaddingClass () {
-      return (this.selectedPaddingDirection && this.selectedPaddingSize)
-        ? `p${this.selectedPaddingDirection}-${this.selectedPaddingSize}`
-        : ''
-    }
-  }
-}
-</script>
-
-<style lang="scss">
-.spacing-playground {
-  .playground-component {
-    background-color: #ffd093;
-    &__padding {
-      background-color: #c9f7db;
-    }
-    &__inner {
-      background-color: white;
-      border: 1px solid rgba(0, 0, 0, 0.2);
-      height: 20px;
-    }
-  }
-}
-</style>
diff --git a/src/vuestic-theme/vuestic-components/vuestic-multi-select/VuesticMultiSelect.demo.vue b/src/vuestic-theme/vuestic-components/vuestic-multi-select/VuesticMultiSelect.demo.vue
deleted file mode 100644
index 346f555ceab427d7ee5c596695a876508612311e..0000000000000000000000000000000000000000
--- a/src/vuestic-theme/vuestic-components/vuestic-multi-select/VuesticMultiSelect.demo.vue
+++ /dev/null
@@ -1,36 +0,0 @@
-<template>
-  <div class="demo-container">
-    <div class="demo-container__item">
-      <vuestic-multi-select
-        label="Select country"
-        v-model="selectedCountries"
-        :options="CountriesList"
-      />
-    </div>
-    <div class="demo-container__item">
-      <vuestic-multi-select
-        label="Select country duplicate"
-        v-model="selectedCountries"
-        :options="CountriesList"
-      />
-    </div>
-  </div>
-</template>
-
-<script>
-
-import CountriesList from '../../../data/CountriesList'
-import VuesticMultiSelect from './VuesticMultiSelect'
-
-export default {
-  components: {
-    VuesticMultiSelect,
-  },
-  data () {
-    return {
-      selectedCountries: [],
-      CountriesList,
-    }
-  },
-}
-</script>
diff --git a/src/vuestic-theme/vuestic-components/vuestic-multi-select/VuesticMultiSelect.vue b/src/vuestic-theme/vuestic-components/vuestic-multi-select/VuesticMultiSelect.vue
deleted file mode 100644
index 6e9a9272e77368ca55630f7610241fdfee1d4ad4..0000000000000000000000000000000000000000
--- a/src/vuestic-theme/vuestic-components/vuestic-multi-select/VuesticMultiSelect.vue
+++ /dev/null
@@ -1,168 +0,0 @@
-<template>
-  <div
-    class="form-group with-icon-right dropdown select-form-group multiselect-form-group"
-    v-dropdown
-    :class="{'has-error': hasErrors()}">
-    <div class="input-group dropdown-toggle">
-      <input
-        readonly
-        :class="{'has-value': !!displayValue}"
-        v-bind:value="displayValue"
-        required/>
-      <label class="control-label">{{label}}</label><va-icon icon="bar"/>
-      <small v-show="hasErrors()" class="help text-danger">{{
-        showRequiredError() }}
-      </small>
-      <va-icon icon="ion ion-ios-arrow-down icon-right input-icon dropdown-ion"/>
-    </div>
-    <div v-if="isClearable">
-      <va-icon
-        icon="fa fa-close icon-cross icon-right input-icon multiselect-form-group__unselect"
-        @click.native="unselectOptions"/>
-    </div>
-    <div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
-      <scrollbar ref="scrollbar">
-        <div class="dropdown-menu-content">
-          <div
-            class="dropdown-item"
-            :class="{'selected': isOptionSelected(option)}"
-            v-for="(option, index) in options"
-            :key="index"
-            @click="toggleSelection(option)"
-          >
-            <span
-              class="ellipsis">{{optionKey ? option[optionKey] : option}}</span>
-            <va-icon icon="fa fa-check selected-icon"/>
-          </div>
-        </div>
-      </scrollbar>
-    </div>
-  </div>
-</template>
-
-<script>
-import Dropdown from '../../vuestic-directives/Dropdown'
-import Scrollbar from '../va-scrollbar/VaScrollbar.vue'
-
-export default {
-  name: 'vuestic-multi-select',
-  components: {
-    Scrollbar,
-  },
-  directives: {
-    dropdown: Dropdown,
-  },
-  data () {
-    return {
-      displayValue: '',
-      validated: false,
-    }
-  },
-  props: {
-    label: String,
-    itemsChosenPlaceholder: {
-      type: String,
-      default: 'chosen',
-    },
-    clearable: {
-      type: Boolean,
-      default: true,
-    },
-    options: Array,
-    value: Array,
-    optionKey: String,
-    required: {
-      type: Boolean,
-      default: false,
-    },
-    name: {
-      type: String,
-      default: 'multiselect',
-    },
-  },
-  mounted () {
-    this.$emit('input', this.value)
-  },
-
-  updated: function () {
-    this.updateDisplayValue(this.value)
-  },
-
-  methods: {
-    unselectOptions () {
-      this.value.splice(0, this.value.length)
-      this.displayValue = ''
-      this.$emit('input', this.value)
-    },
-    toggleSelection (option) {
-      let newVal = this.isOptionSelected(option) ? this.deselectOption(option) : this.selectOption(option)
-      this.updateDisplayValue(newVal)
-      this.$emit('input', newVal)
-    },
-    isOptionSelected (option) {
-      return this.value.includes(option)
-    },
-    selectOption (option) {
-      return this.value.concat(option)
-    },
-    deselectOption (option) {
-      return this.value.filter(item => item !== option)
-    },
-    updateDisplayValue (newVal) {
-      if (newVal.length > 2) {
-        this.displayValue = `${newVal.length}/${this.options.length} ${this.itemsChosenPlaceholder}`
-      } else {
-        this.displayValue = (this.optionKey ? newVal.map(item => item[this.optionKey]) : newVal).join(', ')
-      }
-    },
-    validate () {
-      this.validated = true
-    },
-    isValid () {
-      let isValid = true
-      if (this.required) {
-        isValid = !!this.displayValue
-      }
-      return isValid
-    },
-    hasErrors () {
-      let hasErrors = false
-      if (this.required) {
-        hasErrors = this.validated && !this.displayValue
-      }
-      return hasErrors
-    },
-    showRequiredError () {
-      return `The ${this.name} field is required`
-    },
-  },
-  computed: {
-    isClearable () {
-      return (this.clearable && this.value.length !== 0 && this.displayValue !== '')
-    },
-  },
-}
-</script>
-
-<style lang="scss" scoped>
-@import "../../vuestic-sass/resources/resources";
-
-.multiselect-form-group {
-  &__unselect {
-    margin-right: 20px;
-    cursor: pointer;
-  }
-
-  .dropdown-ion {
-    top: 12px;
-    cursor: pointer;
-  }
-
-  .dropdown-menu {
-    padding: 0;
-    .vuestic-scrollbar {
-      max-height: $dropdown-item-height * 4;
-    }
-  }
-}
-</style>
diff --git a/src/vuestic-theme/vuestic-components/vuestic-simple-select/VuesticSimpleSelect-413.demo.vue b/src/vuestic-theme/vuestic-components/vuestic-simple-select/VuesticSimpleSelect-413.demo.vue
deleted file mode 100644
index 716a20c8df84e11927534dda553f369468af995e..0000000000000000000000000000000000000000
--- a/src/vuestic-theme/vuestic-components/vuestic-simple-select/VuesticSimpleSelect-413.demo.vue
+++ /dev/null
@@ -1,38 +0,0 @@
-<template>
-  <div class="demo-container">
-    <div class="demo-container__item" style="width: 500px;">
-      <vuestic-simple-select
-        label="Position"
-        v-model="value"
-        option-key="description"
-        :options="imagePositions"
-      />
-    </div>
-  </div>
-</template>
-
-<script>
-// Fixes https://github.com/epicmaxco/vuestic-admin/issues/413
-
-import VuesticSimpleSelect from './VuesticSimpleSelect'
-
-export default {
-  name: 'my-component',
-  components: { VuesticSimpleSelect },
-  data: () => {
-    return {
-      value: null,
-      imagePositions: [
-        {
-          id: '1',
-          description: '1',
-        },
-        {
-          id: '2',
-          description: '2',
-        },
-      ],
-    }
-  },
-}
-</script>
diff --git a/src/vuestic-theme/vuestic-components/vuestic-simple-select/VuesticSimpleSelect.demo.vue b/src/vuestic-theme/vuestic-components/vuestic-simple-select/VuesticSimpleSelect.demo.vue
deleted file mode 100644
index e55c19c462bcef0df756e5ebe6229dfd96f7beaf..0000000000000000000000000000000000000000
--- a/src/vuestic-theme/vuestic-components/vuestic-simple-select/VuesticSimpleSelect.demo.vue
+++ /dev/null
@@ -1,36 +0,0 @@
-<template>
-  <div class="demo-container">
-    <div class="demo-container__item">
-      <vuestic-simple-select
-        label="Select country"
-        v-model="selectedCountry"
-        :options="CountriesList"
-      />
-    </div>
-    <div class="demo-container__item">
-      <vuestic-simple-select
-        label="Select country duplicate"
-        v-model="selectedCountry"
-        :options="CountriesList"
-      />
-    </div>
-  </div>
-</template>
-
-<script>
-
-import CountriesList from '../../../data/CountriesList'
-import VuesticSimpleSelect from './VuesticSimpleSelect'
-
-export default {
-  components: {
-    VuesticSimpleSelect,
-  },
-  data () {
-    return {
-      selectedCountry: '',
-      CountriesList,
-    }
-  },
-}
-</script>
diff --git a/src/vuestic-theme/vuestic-components/vuestic-simple-select/VuesticSimpleSelect.vue b/src/vuestic-theme/vuestic-components/vuestic-simple-select/VuesticSimpleSelect.vue
deleted file mode 100644
index 1f56f9325cdd00d7c5e94e5fe8e4aadd3eedbdaf..0000000000000000000000000000000000000000
--- a/src/vuestic-theme/vuestic-components/vuestic-simple-select/VuesticSimpleSelect.vue
+++ /dev/null
@@ -1,228 +0,0 @@
-<template>
-  <div class="vuestic-simple-select">
-    <div
-      class="form-group with-icon-right dropdown select-form-group"
-      v-dropdown="{ isBlocked: true, onDropdownClose: onDropdownClose }"
-      :class="{'has-error': hasErrors()}"
-    >
-      <div
-        class="input-group dropdown-toggle vuestic-simple-select__dropdown-toggle">
-        <div>
-          <input
-            @focus="showDropdown()"
-            :class="{'has-value': !!value}"
-            v-model="displayValue"
-            :name="name"
-            :options="options"
-          >
-          <label class="control-label">{{label}}</label><va-icon icon="bar"/>
-          <small v-show="hasErrors()" class="help text-danger">
-            {{ showRequiredError() }}
-          </small>
-        </div>
-        <va-icon
-          icon="ion ion-ios-arrow-down icon-right input-icon vuestic-simple-select__dropdown-arrow"
-          @click="showDropdown"
-        />
-      </div>
-      <div v-if="isClearable">
-        <va-icon
-          icon="fa fa-close icon-cross icon-right input-icon vuestic-simple-select__unselect"
-          @click="unselectOption"
-        />
-      </div>
-      <div
-        class="dropdown-menu vuestic-simple-select__dropdown-menu"
-        aria-labelledby="dropdownMenuButton">
-        <scrollbar ref="scrollbar">
-          <div
-            class="dropdown-menu-content vuestic-simple-select__dropdown-menu-content">
-            <div
-              class="dropdown-item vuestic-simple-select__dropdown-item"
-              v-for="(option, index) in filteredList"
-              :key="index"
-              :class="{'selected': isOptionSelected(option)}"
-              @click="toggleSelection(option)"
-            >
-            <span
-              class="ellipsis">{{optionKey ? option[optionKey] : option}}</span>
-            </div>
-          </div>
-        </scrollbar>
-      </div>
-    </div>
-  </div>
-</template>
-
-<script>
-import Dropdown from '../../vuestic-directives/Dropdown'
-import Scrollbar from '../va-scrollbar/VaScrollbar.vue'
-
-export default {
-  name: 'vuestic-simple-select',
-  components: {
-    Scrollbar,
-  },
-  directives: {
-    dropdown: Dropdown,
-  },
-  props: {
-    label: String,
-    options: Array,
-    value: {
-      default: '',
-      required: true,
-    },
-    optionKey: String,
-    required: {
-      type: Boolean,
-      default: false,
-    },
-    clearable: {
-      type: Boolean,
-      default: true,
-    },
-    name: {
-      type: String,
-      default: 'simple-select',
-    },
-  },
-  data () {
-    return {
-      validated: false,
-      displayValue: this.value || '',
-      selectedValue: this.value,
-    }
-  },
-  watch: {
-    value: {
-      handler (value) {
-        if (!value || !this.optionKey) {
-          this.displayValue = value || ''
-          this.selectedValue = value || ''
-          return
-        }
-        this.selectedValue = value[this.optionKey]
-        this.displayValue = value[this.optionKey]
-      },
-      immediate: true,
-    },
-  },
-  computed: {
-    filteredList () {
-      const optionKey = this.optionKey
-      const displayValue = this.displayValue
-      if (displayValue === '') {
-        return this.options
-      } else {
-        // HACK This is done poorly.
-        return this.options.filter(function (item) {
-          if (optionKey && item && item[optionKey]) {
-            // option is object
-            if (displayValue) {
-              return item[optionKey].toLowerCase()
-                .search(displayValue.toLowerCase()) === 0
-            }
-          } else {
-            // option is string
-            return (item + '').toLowerCase()
-              .search(displayValue.toLowerCase()) === 0
-          }
-        })
-      }
-    },
-    isClearable () {
-      return (this.clearable && this.selectedValue !== '' && this.displayValue !== '' && this.selectedValue !== undefined)
-    },
-    placeholder () {
-      if (this.optionKey && this.selectedValue) {
-        return this.selectedValue[this.optionKey]
-      } else {
-        return this.selectedValue
-      }
-    },
-  },
-  methods: {
-    onDropdownClose () {
-      if (!this.value) {
-        this.displayValue = ''
-      }
-      if (this.value && this.optionKey) {
-        this.displayValue = this.value[this.optionKey]
-      }
-    },
-    toggleSelection (option) {
-      this.isOptionSelected(option) ? this.unselectOption() : this.selectOption(option)
-    },
-    unselectOption () {
-      this.selectedValue = ''
-      this.$emit('input', this.selectedValue)
-    },
-    showDropdown () {
-      this.displayValue = ''
-    },
-    isOptionSelected (option) {
-      if (this.optionKey) {
-        return this.selectedValue === option[this.optionKey]
-      } else {
-        return this.selectedValue === option
-      }
-    },
-    selectOption (option) {
-      if (!option) {
-        this.displayValue = ''
-      }
-      if (option && this.optionKey) {
-        this.displayValue = option[this.optionKey]
-      }
-      this.selectedValue = option
-      this.$emit('input', option)
-    },
-    validate () {
-      this.validated = true
-    },
-    isValid () {
-      let isValid = true
-      if (this.required) {
-        isValid = !!this.value
-      }
-      return isValid
-    },
-    hasErrors () {
-      let hasErrors = false
-      if (this.required) {
-        hasErrors = this.validated && !this.value
-      }
-      return hasErrors
-    },
-    showRequiredError () {
-      return `The ${this.name} field is required`
-    },
-  },
-}
-</script>
-
-<style lang="scss">
-@import "../../vuestic-sass/resources/resources";
-
-.vuestic-simple-select {
-
-  &__unselect {
-    margin-right: 20px;
-    cursor: pointer;
-  }
-
-  .vuestic-simple-select__dropdown-arrow.vuestic-simple-select__dropdown-arrow {
-    top: 12px;
-    cursor: pointer;
-  }
-
-  &__dropdown-menu {
-    padding: 0;
-
-    .vuestic-scrollbar {
-      max-height: $dropdown-item-height * 4;
-    }
-  }
-}
-</style>
diff --git a/src/vuestic-theme/vuestic-plugin.js b/src/vuestic-theme/vuestic-plugin.js
index f3992996e34a0ac96b043a490bf382089b1c49d3..fcc8f293d53d84636f4cc5a3dc08611edff164fa 100644
--- a/src/vuestic-theme/vuestic-plugin.js
+++ b/src/vuestic-theme/vuestic-plugin.js
@@ -1,8 +1,6 @@
 import VaNotification from './vuestic-components/va-notification/VaNotification.vue'
 import Breadcrumbs
   from './vuestic-components/vuestic-breadcrumbs/VuesticBreadcrumbs.vue'
-import Chart from './vuestic-components/vuestic-chart/VuesticChart.vue'
-import Chat from './vuestic-components/vuestic-chat/VuesticChat.vue'
 import VaCheckbox from './vuestic-components/va-checkbox/VaCheckbox.vue'
 import VaProgressCircle
   from './vuestic-components/va-progress-bar/progress-types/VaProgressCircle.vue'
@@ -16,8 +14,6 @@ import VaSlider
 import MediumEditor
   from './vuestic-components/vuestic-medium-editor/VuesticMediumEditor.vue'
 import Modal from './vuestic-components/va-modal/VaModal.vue'
-import MultiSelect
-  from './vuestic-components/vuestic-multi-select/VuesticMultiSelect.vue'
 import Popover from './vuestic-components/vuestic-popover/VuesticPopover.vue'
 import PreLoader
   from './vuestic-components/va-preloader/VaPreLoader.vue'
@@ -36,11 +32,11 @@ import VaButtonToggle
 import VaPagination
   from './vuestic-components/va-pagination/VaPagination.vue'
 import RadioButton
-  from './vuestic-components/vuestic-radio-button/VuesticRadioButton'
+  from './vuestic-components/va-radio-button/VaRadioButton'
 import Scrollbar
   from './vuestic-components/va-scrollbar/VaScrollbar.vue'
-import SimpleSelect
-  from './vuestic-components/vuestic-simple-select/VuesticSimpleSelect.vue'
+import VaSelect
+  from './vuestic-components/va-select/VaSelect.vue'
 import SocialNews
   from './vuestic-components/vuestic-social-news/VuesticSocialNews.vue'
 import Switch from './vuestic-components/vuestic-switch/VuesticSwitch.vue'
@@ -96,15 +92,12 @@ const VuesticPlugin = {
     [
       VaNotification,
       Breadcrumbs,
-      Chart,
-      Chat,
       VaCheckbox,
       VaProgressBar,
       DataTable,
       Feed,
       VaProgressCircle,
       Modal,
-      MultiSelect,
       PreLoader,
       ProfileCard,
       VaProgressBar,
@@ -117,7 +110,7 @@ const VuesticPlugin = {
       VaPagination,
       RadioButton,
       Scrollbar,
-      SimpleSelect,
+      VaSelect,
       SocialNews,
       Switch,
       Tabs,
diff --git a/src/vuestic-theme/vuestic-sass/global/_typography.scss b/src/vuestic-theme/vuestic-sass/global/_typography.scss
index a85628fb206a2e45077f7c343fe8c060c0cca0e3..7ad3114f77f83bdd5bd2417b46f3e591c4dad700 100644
--- a/src/vuestic-theme/vuestic-sass/global/_typography.scss
+++ b/src/vuestic-theme/vuestic-sass/global/_typography.scss
@@ -1,6 +1,7 @@
 
 ::selection {
   background-color: $text-selected;
+  color: $white;
 }
 
 .link {
@@ -13,24 +14,22 @@
 
 .link, .link-secondary {
   cursor: pointer;
+
   &:hover {
     color: $va-link-color-hover;
   }
+
   &:active {
     color: $va-link-color-active;
   }
+
   &:visited {
     color: $va-link-color-visited;
   }
 }
 
 .title {
- color: $vue-green;
- font-size: 10px;
- letter-spacing: 0.6px;
- line-height: 1.2;
- font-weight: bold;
- text-transform: uppercase;
+  @include va-title();
 
   &--info {
     color: $theme-blue-dark;
@@ -43,47 +42,62 @@
   &--warning {
     color: $theme-warning;
   }
+
+  &--gray {
+    color: $brand-secondary;
+  }
 }
 
 .text {
   &--bold {
     font-weight: bold;
   }
+
   &--highlighted {
     background-color: $text-highlighted;
   }
+
   &--left {
     text-align: left !important;
   }
+
   &--right {
     text-align: right !important;
   }
+
   &--center {
     text-align: center !important;
   }
+
   &--uppercase {
     text-transform: uppercase !important;
   }
+
   &--lowercase {
     text-transform: lowercase !important;
   }
+
   &--capitalize {
     text-transform: capitalize !important;
   }
+
   &--no-wrap {
     white-space: nowrap !important;
   }
+
   &--truncate {
     white-space: nowrap !important;
     overflow: hidden !important;
     text-overflow: ellipsis !important;
   }
+
   &--code {
     color: $white;
     font-family: "Source Code Pro";
     background-color: $vue-darkest-blue;
     padding: 0.1rem 0.2rem;
   }
+
   &--secondary {
     opacity: 0.4;
   }
@@ -97,6 +111,7 @@
 
   p {
     margin-bottom: 0.5rem;
+
     &:last-child {
       margin-bottom: 0;
     }
@@ -168,6 +183,38 @@ ol.va-ordered {
   }
 }
 
+.va-table {
+  width: 100%;
+  border-collapse: collapse;
+  @extend .mb-3;
+
+  thead tr {
+    border-bottom: 2px solid $vue-darkest-blue;
+
+    td {
+      @extend .title;
+      color: $vue-darkest-blue;
+    }
+  }
+
+  td {
+    padding: .625rem;
+    font-size: .875rem;
+    line-height: 1.43;
+    color: $vue-darkest-blue;
+  }
+
+  &.striped {
+    tbody tr:nth-of-type(odd) {
+      background-color: $white;
+    }
+
+    tbody tr:nth-of-type(even) {
+      background-color: $light-gray3;
+    }
+  }
+}
+
 .vue-misc {
   margin-top: 5.625rem;
   margin-bottom: 2rem;
diff --git a/src/vuestic-theme/vuestic-sass/global/color-themes.demo.vue b/src/vuestic-theme/vuestic-sass/global/color-themes.demo.vue
index 3120848941fa743aa3997a8ba1cb6de392e7d5a9..c60789598324d36597472cbdb904460242db4b1b 100644
--- a/src/vuestic-theme/vuestic-sass/global/color-themes.demo.vue
+++ b/src/vuestic-theme/vuestic-sass/global/color-themes.demo.vue
@@ -61,7 +61,7 @@
 import VaButton from './../../vuestic-components/va-button/VaButton'
 import VaNotification from './../../vuestic-components/va-notification/VaNotification'
 import VaProgressBar from './../../vuestic-components/va-progress-bar/progress-types/VaProgressBar'
-import VaColorPickerInput from '../../vuestic-components/vuestic-color-picker/VuesticColorPickerInput'
+import VaColorPickerInput from '../../vuestic-components/va-color-picker/VuesticColorPickerInput'
 import VaSidebar from '../../vuestic-components/va-sidebar/VaSidebar'
 import SidebarLinkGroup from './../../../components/layout/app-sidebar/components/SidebarLinkGroup'
 import SidebarLink from './../../../components/layout/app-sidebar/components/SidebarLink'
diff --git a/src/vuestic-theme/vuestic-sass/icons/fonts.scss b/src/vuestic-theme/vuestic-sass/icons/fonts.scss
index 5a907a9c4bc9faaa6418d886ec5118df44a3c6df..485d2cdaf0c87c5f53fd0cc13632ddfce56b4c77 100644
--- a/src/vuestic-theme/vuestic-sass/icons/fonts.scss
+++ b/src/vuestic-theme/vuestic-sass/icons/fonts.scss
@@ -17,15 +17,3 @@ $icon-font-name: 'glyphicons-halflings-regular';
 $icon-font-svg-id: 'glyphicons_halflingsregular';
 $icon-font-path: './../fonts/';
 
-// Fonts //
-//@import url(https://fonts.googleapis.com/css?family=Source+Sans+Pro);
-//
-//@font-face {
-//  font-family: 'Glyphicons Halflings';
-//  src: url(if($bootstrap-sass-asset-helper, twbs-font-path('#{$icon-font-path}#{$icon-font-name}.eot'), '#{$icon-font-path}#{$icon-font-name}.eot'));
-//  src: url(if($bootstrap-sass-asset-helper, twbs-font-path('#{$icon-font-path}#{$icon-font-name}.eot?#iefix'), '#{$icon-font-path}#{$icon-font-name}.eot?#iefix')) format('eot'),
-//  url(if($bootstrap-sass-asset-helper, twbs-font-path('#{$icon-font-path}#{$icon-font-name}.woff2'), '#{$icon-font-path}#{$icon-font-name}.woff2')) format('woff2'),
-//  url(if($bootstrap-sass-asset-helper, twbs-font-path('#{$icon-font-path}#{$icon-font-name}.woff'), '#{$icon-font-path}#{$icon-font-name}.woff')) format('woff'),
-//  url(if($bootstrap-sass-asset-helper, twbs-font-path('#{$icon-font-path}#{$icon-font-name}.ttf'), '#{$icon-font-path}#{$icon-font-name}.ttf')) format('truetype'),
-//  url(if($bootstrap-sass-asset-helper, twbs-font-path('#{$icon-font-path}#{$icon-font-name}.svg##{$icon-font-svg-id}'), '#{$icon-font-path}#{$icon-font-name}.svg##{$icon-font-svg-id}')) format('svg');
-//}
diff --git a/src/vuestic-theme/vuestic-sass/resources/_mixins.scss b/src/vuestic-theme/vuestic-sass/resources/_mixins.scss
index dc255386cdbe23d0405c697b930442b35935e93f..5e4950a1a6b3e34bed883d8b9ac50b0b5ce6cbe7 100644
--- a/src/vuestic-theme/vuestic-sass/resources/_mixins.scss
+++ b/src/vuestic-theme/vuestic-sass/resources/_mixins.scss
@@ -1,5 +1,14 @@
 @import "../../vuestic-components/vuestic-grid/grid-mixins";
 
+@mixin va-title() {
+  color: $vue-green;
+  font-size: .625rem;
+  letter-spacing: 0.6px;
+  line-height: 1.2;
+  font-weight: bold;
+  text-transform: uppercase;
+}
+
 @mixin flex-center () {
   display: flex;
   justify-content: center;
diff --git a/src/vuestic-theme/vuestic-sass/resources/_variables.scss b/src/vuestic-theme/vuestic-sass/resources/_variables.scss
index dd19b868498fe54001b2d5f11e559897edd37c69..8fd59f90fd4303537a466af9aa3710359393cfbf 100644
--- a/src/vuestic-theme/vuestic-sass/resources/_variables.scss
+++ b/src/vuestic-theme/vuestic-sass/resources/_variables.scss
@@ -62,17 +62,20 @@ $theme-colors: (
   "pale": $theme-pale
 );
 
+$transition-primary: 0.3s cubic-bezier(.25,.8,.50,1); // swing
+$transition-secondary: 0.2s cubic-bezier(0.4, 0.0, 0.6, 1); // ease-in-out
+
 // Layout //
 $body-bg: $light-gray;
 $top-nav-bg: $dark-blue;
 $body-color: $vue-darkest-blue !default;
 $layout-padding: 24px;
-$layout-padding-right: 44px;
+$layout-padding-right: 2rem;
 $nav-button-bg: linear-gradient(to right, #484b4f, #161616);
 
 $top-nav-height: 72px;
 
-$nav-padding-left: $layout-padding;
+$nav-padding-left: 1rem;
 $nav-padding-right: $layout-padding-right;
 $navbar-brand-container-left: 75px;
 
@@ -82,7 +85,6 @@ $sidebar-width--hidden: 56px;
 $sidebar-top: $top-nav-height;
 $sidebar-left--hidden: calc(#{$layout-padding} + #{$sidebar-width--hidden});
 $sidebar-left: $layout-padding;
-$min-z-index: -1000;
 
 $content-wrap-ml: calc(#{$sidebar-left} + #{$sidebar-width});
 $content-wrap-pb: $layout-padding;
@@ -90,6 +92,15 @@ $made-by-footer-pb: 27px;
 
 $greeny-box-shadow: 0 4px 9.6px 0.4px rgba($vue-green, .5);
 
+$sidebar-left: $layout-padding;
+
+$content-wrap-ml: calc(#{$sidebar-left} + #{$sidebar-width});
+$content-wrap-pb: $layout-padding;
+$made-by-footer-pb: 27px;
+
+$greeny-box-shadow: 0 4px 9.6px 0.4px rgba($vue-green, .5);
+$gray-box-shadow: 0 2px 3px 0 rgba(98, 106, 119, 0.25);
+
 //Auth
 $auth-wallpaper-ivuestic-h: 2.625rem;
 $auth-wallpaper-oblique-line: $dark-gray;
@@ -259,8 +270,8 @@ $chip-with-icon-wrapper-padding-nrm: 0.5rem;
 $chip-with-icon-content-padding-nrm: 0.5rem;
 
 //Dropdowns
-$dropdown-box-shadow: $greeny-box-shadow;
-$dropdown-background: $darkest-gray;
+$dropdown-box-shadow: $gray-box-shadow;
+$dropdown-background: $light-gray3;
 $dropdown-item-height: 40px;
 $dropdown-menu-padding-y: 10px;
 $dropdown-menu-padding-x: 0;
@@ -361,3 +372,8 @@ $card-box-shadow: 0 2px 3px 0 rgba(52, 56, 85, 0.25);
 $card-title-font-size: 0.625rem;
 $card-title-letter-spacing: 0.0375rem;
 $card-title-color: #104fca;
+
+// Datepickers
+
+$datepicker-box-shadow: 0 2px 3px 0 rgba(98, 106, 119, 0.25);
+
diff --git a/yarn.lock b/yarn.lock
index ca487cd0b8b6c787a8e9597e6aaa272f4fa6d39f..e16e3b749bb73c6c2db2f42319dd1200fe4061d8 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -6867,16 +6867,6 @@ lodash._reinterpolate@~3.0.0:
   resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d"
   integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=
 
-lodash.assign@^4.2.0:
-  version "4.2.0"
-  resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7"
-  integrity sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=
-
-lodash.clonedeep@^4.3.2:
-  version "4.5.0"
-  resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
-  integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=
-
 lodash.defaultsdeep@^4.6.0:
   version "4.6.0"
   resolved "https://registry.yarnpkg.com/lodash.defaultsdeep/-/lodash.defaultsdeep-4.6.0.tgz#bec1024f85b1bd96cbea405b23c14ad6443a6f81"
@@ -6922,11 +6912,6 @@ lodash.merge@^4.6.0:
   resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.1.tgz#adc25d9cb99b9391c59624f379fbba60d7111d54"
   integrity sha512-AOYza4+Hf5z1/0Hztxpm2/xiPZgi/cjMqdnKTUWTBSKchJlxXXuUSxCCl8rJlf4g6yww/j6mA8nC8Hw/EZWxKQ==
 
-lodash.mergewith@^4.6.0:
-  version "4.6.1"
-  resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.1.tgz#639057e726c3afbdb3e7d42741caa8d6e4335927"
-  integrity sha512-eWw5r+PYICtEBgrBE5hhlT6aAa75f411bgDz/ZL2KZqYV03USvucsxcHUIlGTDTECs1eunpI7HOV7U+WLDvNdQ==
-
 lodash.once@^4.1.1:
   version "4.1.1"
   resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac"
@@ -7453,7 +7438,12 @@ mute-stream@0.0.7:
   resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab"
   integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=
 
-nan@^2.10.0, nan@^2.9.2:
+nan@^2.13.2:
+  version "2.14.0"
+  resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c"
+  integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==
+
+nan@^2.9.2:
   version "2.13.1"
   resolved "https://registry.yarnpkg.com/nan/-/nan-2.13.1.tgz#a15bee3790bde247e8f38f1d446edcdaeb05f2dd"
   integrity sha512-I6YB/YEuDeUZMmhscXKxGgZlFnhsn5y0hgOZBadkzfTRrZBtJDZeg6eQf7PYMIEclwmorTKK8GztsyOUSVBREA==
@@ -7629,10 +7619,10 @@ node-releases@^1.1.11:
   dependencies:
     semver "^5.3.0"
 
-node-sass@^4.9.0:
-  version "4.11.0"
-  resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.11.0.tgz#183faec398e9cbe93ba43362e2768ca988a6369a"
-  integrity sha512-bHUdHTphgQJZaF1LASx0kAviPH7sGlcyNhWade4eVIpFp6tsn7SV8xNMTbsQFpEV9VXpnwTTnNYlfsZXgGgmkA==
+node-sass@^4.12.0:
+  version "4.12.0"
+  resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.12.0.tgz#0914f531932380114a30cc5fa4fa63233a25f017"
+  integrity sha512-A1Iv4oN+Iel6EPv77/HddXErL2a+gZ4uBeZUy+a8O35CFYTXhgA8MgLCWBtwpGZdCvTvQ9d+bQxX/QC36GDPpQ==
   dependencies:
     async-foreach "^0.1.3"
     chalk "^1.1.1"
@@ -7641,12 +7631,10 @@ node-sass@^4.9.0:
     get-stdin "^4.0.1"
     glob "^7.0.3"
     in-publish "^2.0.0"
-    lodash.assign "^4.2.0"
-    lodash.clonedeep "^4.3.2"
-    lodash.mergewith "^4.6.0"
+    lodash "^4.17.11"
     meow "^3.7.0"
     mkdirp "^0.5.1"
-    nan "^2.10.0"
+    nan "^2.13.2"
     node-gyp "^3.8.0"
     npmlog "^4.0.0"
     request "^2.88.0"
@@ -10800,10 +10788,10 @@ vm-browserify@0.0.4:
   dependencies:
     indexof "0.0.1"
 
-vue-book@0.1.0-alpha.14:
-  version "0.1.0-alpha.14"
-  resolved "https://registry.yarnpkg.com/vue-book/-/vue-book-0.1.0-alpha.14.tgz#8e4ccc6fd7f0a34f83e6647fd5f0f3829c186c5b"
-  integrity sha512-I3r0iK9oNMab44Ry0ZCKqkkfoQNcYh1nmKxfktBORq8VvrB/ODx2D49P8h98jMCdI5NCdw3H6U5y8Vc4bTsW7g==
+vue-book@0.1.0-alpha.17:
+  version "0.1.0-alpha.17"
+  resolved "https://registry.yarnpkg.com/vue-book/-/vue-book-0.1.0-alpha.17.tgz#4661bfc5a6813ccdfc5ce9ecb35cdcddbd163366"
+  integrity sha512-8BpuuImZfM3dZ1zsTdBA0fxpcbZ3VJ9JsPrNVVDqx0Gn9H5qgZXDGKmLnN4kSfXO5CZjDPns0Sj+ZeofdWt+Dg==
 
 vue-bulma-expanding@0.0.1:
   version "0.0.1"