# ivyforms/0.2/frontend/src/views/_components/input/IvySelectInput.vue

The Innovative Form Builder – IvyForms, version 0.2. 288 lines.

- Page: https://pluginprobe.com/plugins/ivyforms/0.2/code/frontend/src/views/_components/input/IvySelectInput.vue
- Raw: https://pluginprobe.com/plugins/ivyforms/0.2/raw/frontend/src/views/_components/input/IvySelectInput.vue
- Modified: 2025-07-24T13:31:58+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/ivyforms/0.2/code/frontend/src/views/_components/input/IvySelectInput.vue#L10-L20`.

```vue
<template>
  <ElSelect
    ref="elInputRef"
    v-bind="{ ...$attrs, ...$props }"
    v-model="model"
    :placeholder="props.placeholder"
    :disabled="props.disabled"
    :multiple="props.multiple"
    :collapse-tags="props.multiple"
    :clearable="props.clearable"
    :class="[
      {
        'is-clearable': props.clearable,
        'is-filled': props.filled,
        'is-secondary': isSecondary,
      },
      'ivyforms-form-item-select',
    ]"
    :max-collapse-tags="props.maxTags"
    :aria-label="computedAriaLabel"
  >
    <template v-if="!!slots['prefix'] || iconStart" #prefix>
      <slot name="prefix">
        <IvyIcon
          v-if="iconStart"
          :name="iconStart"
          :category="iconStartCategory"
          :type="iconStartType"
          class="ivyforms-input__icon-start"
          size="l"
          color="var(--map-base-dusk-symbol-2)"
        />

        <!--            TODO Add the avatar component-->
        <IvyIcon v-if="props.avatar" class="ivyforms-input__avatar" name="user" size="l" />
        <!--            <IvyAvatar-->
        <!--                v-if="props.avatar"-->
        <!--                class="ivyforms-input__avatar"-->
        <!--            />-->
      </slot>
    </template>
    <slot />
  </ElSelect>
</template>

<script setup lang="ts">
import { useSlots, inject, computed } from 'vue'
import type { IconCategory } from '@/types/icons/icon-category'
import type { IconType } from '@/types/icons/icon-type'
import { useLabels } from '@/composables/useLabels'
const { getLabel } = useLabels()

interface Props {
  modelValue: string | string[] | null | undefined
  label?: string
  placeholder?: string
  iconStart?: string
  iconEnd?: string
  iconStartCategory?: IconCategory
  iconEndCategory?: IconCategory
  avatar?: string
  iconStartType?: IconType
  iconEndType?: IconType
  filled?: boolean
  prefix?: string
  suffix?: string
  clearable?: boolean
  disabled?: boolean
  multiple?: boolean
  maxTags?: number
  ariaLabel?: string
}

const props = withDefaults(defineProps<Props>(), {
  placeholder: '',
  iconStartCategory: 'global',
  iconEndCategory: 'global',
  iconStartType: 'outline',
  iconEndType: 'outline',
  label: '',
  iconStart: '',
  iconEnd: '',
  avatar: '',
  prefix: '',
  suffix: '',
  maxTags: 3,
  ariaLabel: '',
})

const isSecondary = inject('isSecondary', false)

const slots = useSlots()

const emit = defineEmits(['update:modelValue'])

const model = computed({
  get: () => props.modelValue,
  set: (value) => emit('update:modelValue', value),
})

const computedAriaLabel = computed(() => props.ariaLabel || getLabel('select'))
</script>

<style lang="scss">
.ivyforms-form-item-select {
  .el-select__wrapper {
    border: 1px solid var(--map-base-dusk-stroke--2);
    background: var(--map-base-dusk-o05);
    border-radius: var(--Radius-radius-md, 8px);
    display: flex;
    align-items: center;
    gap: var(--Spacing-sm, 8px);
    padding: var(--Spacing-sm, 8px) var(--Spacing-lg, 12px);
    height: 40px;
    box-shadow: none !important;

    &:hover,
    &.is-hovering:not(.is-focused) {
      border: 1px solid var(--map-base-dusk-stroke-0);
    }

    &:focus,
    &:active,
    &.is-active,
    &.is-focused {
      border: 1px solid var(--map-base-brand-stroke-0);

      .el-tag {
        background: var(--map-base-brand-o10);
        color: var(--map-base-brand-symbol-0);

        .el-tag__close svg {
          color: var(--map-base-brand-symbol-0);
          width: 14px;
          height: 14px;
        }
      }
    }

    .el-select__selection {
      padding: 0;
      font-size: 16px;
      font-weight: 400;
      line-height: 22px;
      color: var(--map-base-text-0);
      background-color: transparent;
      display: flex;
      align-items: center;
      gap: 4px;
      flex: 1 0 0;
    }

    .el-select__suffix .el-icon.el-select__caret.el-select__icon {
      background: url('../../../assets/icons/arrows/line/chevron-down.svg') no-repeat center;
      background-size: contain;
      width: 16px;
      height: 16px;
      cursor: pointer;
      opacity: 1 !important;

      &.el-select__clear {
        background: url('../../../assets/icons/global/fill-duo/close-circle.svg') no-repeat center;
      }
    }
  }

  &.is-secondary .el-select__wrapper {
    &:active,
    &:focus,
    &.is-focused,
    &.is-active {
      border: 1px solid var(--map-base-purple-stroke-0);

      .el-tag {
        background: var(--map-base-purple-o10);
        color: var(--map-base-purple-symbol-0);

        .el-tag__close svg {
          color: var(--map-base-purple-symbol-0);
          width: 14px;
          height: 14px;
        }
      }
    }

    .el-select__wrapper {
      // Active & Focus
      &:active,
      &:focus,
      &.is-focused,
      &.is-active {
        border: 1px solid var(--map-base-purple-stroke-0);
      }
    }
  }

  // Filled
  &.is-filled {
    .el-select__wrapper {
      border: 1px solid var(--map-base-dusk-stroke--2);
      background: var(--map-base-dusk-o05);

      &:hover,
      &.is-hovering {
        border: 1px solid var(--map-base-dusk-stroke-0);
      }

      &:active,
      &.is-active,
      &:focus,
      &.is-focused {
        border: 1px solid var(--map-base-brand-stroke-0);

        .el-tag {
          background: var(--map-base-brand-o10);
          color: var(--map-base-brand-symbol-0);

          .el-tag__close svg {
            color: var(--map-base-brand-symbol-0);
            width: 14px;
            height: 14px;
          }
        }
      }

      .el-tag {
        background: var(--map-base-dusk-o20);
        color: var(--map-base-text-0);

        .el-tag__close svg {
          color: var(--map-base-text-0);
          width: 14px;
          height: 14px;
        }
      }
    }

    &.is-error .el-select__wrapper {
      border: 1px solid var(--map-status-error-symbol-0);
    }

    &.is-warning .el-select__wrapper {
      border: 1px solid var(--map-status-warning-stroke-0);
    }

    .el-tag {
      font-size: 14px;
      font-weight: 400;
      line-height: 20px;
      display: flex;
      padding: 2px 4px 2px 8px;
      align-items: center;
      gap: 4px;
      cursor: pointer;
      background: var(--map-base-dusk-o20);
      color: var(--map-base-text-0);

      .el-tag__close {
        background: url('../../../assets/icons/global/outline/close.svg') no-repeat center;
        background-size: contain;
        width: 16px;
        height: 16px;
        cursor: pointer;
        margin: 0;

        svg {
          color: var(--map-base-text-0);
          width: 14px;
          height: 14px;
        }

        &:hover {
          background: url('../../../assets/icons/global/outline/close.svg') no-repeat center;
          width: 16px;
          height: 16px;
        }
      }
    }
  }
}

.el-select__popper {
  .el-scrollbar {
    background-color: transparent;
  }
}
</style>

```
