Copy environment

Select

<div class="textfield select ">
    <label class="textfield__label select__label  " for="select1">
        Select label
    </label>
    <div class="textfield__inner">
        <select name="select" id="select1" class="textfield__input select__input">
            <option value="1">
                Lorem ipsum dolor sit amet, consectetur adipisicing elit. Veritatis error velit quidem alias nihil mollitia temporibus, maxime dicta repellat. Perspiciatis veniam doloribus, quia corporis commodi sed omnis adipisci facilis nisi.
            </option>
            <option value="2">
                Option 2
            </option>
            <option value="3">
                Option 3
            </option>
        </select>
        <svg class="icon  select__icon" focusable="false">
            <use href="../../inc/svg/global.4609ec92109fc41e7ad4764ef897ea8e.svg#"></use>
        </svg>

    </div>
</div>
{% set input %}
    <select
        name="{{ data.name }}"
        id="{{ data.id }}"
        {% if 'select--multiple' in modifier %} multiple{% endif %}
        {% if 'select--search' in modifier %} data-search="true"{% endif %}
        class="textfield__input select__input"
        {% if data.isDisabled %} disabled{% endif %}
        {% if 'select--search' in modifier %} data-no-results-text="{{ data.noResultsText }}"{% endif %}
        {% if 'select--multiple' in modifier %} data-remove-item-text="{{ data.removeItemText }}"{% endif %}
        {{ data.attributes }}
    >
        {% if data.placeholder or data.hasPlaceholder %}
            <option value="placeholder" disabled selected>
                {% if data.placeholder %}
                    {{ data.placeholder }}
                {% endif %}
            </option>
        {% endif %}
        {% for option in data.options %}
            <option
                value="{{ option.value }}"
                {% if option.isSelected %} selected {% endif %}
            >
                {{ option.name }}
            </option>
        {% endfor %}
    </select>
    {% include '@icon' with { class: 'select__icon', modifier: '', name: data.iconName } %}
{% endset %}

{% include '@textfield' with {
    data: data,
    input: input,
    class: 'select ' ~ class,
    modifier: modifier,
    labelClass: 'select__label' ~ ' ' ~ labelClass
} %}
{
  "language": "en-US",
  "data": {
    "label": "Select label",
    "id": "select1",
    "name": "select",
    "options": [
      {
        "name": "Lorem ipsum dolor sit amet, consectetur adipisicing elit. Veritatis error velit quidem alias nihil mollitia temporibus, maxime dicta repellat. Perspiciatis veniam doloribus, quia corporis commodi sed omnis adipisci facilis nisi.",
        "value": "1"
      },
      {
        "name": "Option 2",
        "value": "2"
      },
      {
        "name": "Option 3",
        "value": "3"
      }
    ]
  }
}
  • Content:
    .select {
        position: relative;
        margin: 0;
        cursor: pointer;
    
        &.is-disabled {
            cursor: default;
        }
    }
    
    .select__icon {
        position: absolute;
        top: 50%;
        right: 16px;
        transform: translateY(-50%);
        font-size: 24px;
        pointer-events: none;
    
        .select__container.is-open + & {
            transform: translateY(-50%) rotate(180deg);
        }
    }
    
    .select__inner {
        padding-right: calc(24px + 4px);
        min-height: 32px;
        height: auto;
        box-shadow: $elevation-01;
        display: flex;
        align-items: center;
    
        .select__container.is-focused & {
            border-color: $L-border-focus;
        }
    }
    
    .select__dropdown {
        visibility: hidden;
        z-index: 2;
        position: absolute;
        top: 100%;
        width: 100%;
        background-color: $L-background-weak;
        border: none;
        overflow: hidden;
        word-break: break-all; /* stylelint-disable-line plugin/no-unsupported-browser-features */
        will-change: visibility;
        border-radius: $border-radius-base;
        box-shadow: $elevation-02;
    
        .select--search & {
            padding-top: 48px;
        }
    
        .select__container.is-flipped & {
            top: auto;
            bottom: 100%;
    
            .select--search & {
                padding-top: 0;
                padding-bottom: 48px;
            }
        }
    
        .select__container.is-open & {
            visibility: visible;
        }
    }
    
    .select__choices-input {
        background: transparent;
        border: none;
        appearance: none;
        height: 48px;
        display: none;
        width: 100% !important; /* overwrite plugin inline styles */
        padding: 10px 16px;
        z-index: -1;
        pointer-events: none;
        position: absolute;
        top: 100%;
        left: 0;
    
        .select__container.is-flipped & {
            top: auto;
            bottom: 100%;
        }
    
        .select--multiple:not(.select--search) & {
            color: transparent;
            outline: none;
        }
    
        .select--search .select__container.is-open & {
            pointer-events: auto;
        }
    
        &:not(select) {
            display: block;
            z-index: 3;
        }
    
        &::-ms-expand {
            display: none;
        }
    }
    
    .select__list {
        .select__dropdown & {
            padding: 8px 0;
            max-height: 220px;
            overflow-y: auto;
            will-change: scroll-position;
    
            .select--search & {
                border-top: 1px solid $L-border;
            }
    
            .select__container.is-flipped & {
                .select--search & {
                    border-top: 0;
                    border-bottom: 1px solid $L-border;
                }
            }
        }
    }
    
    .select__list--single,
    .select__list--multiple {
        overflow: hidden;
        white-space: nowrap;
        padding: 4px 0;
        width: 100%;
        height: 100%;
    }
    
    .select__list--multiple {
        overflow: visible;
        white-space: normal;
        padding: 10px 0 4px;
        line-height: 0;
    }
    
    .select__item {
        padding: 8px 16px;
        color: $L-text-black;
        font-size: $font-size-small;
        line-height: $line-height-base;
    
        .select__list--single & {
            padding: 0;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
            color: $L-text;
        }
    
        .select__list--multiple & {
            display: inline-block;
            background-color: $L-background-medium;
            font-size: 12px;
            padding: 2px 24px 2px 8px;
            margin-bottom: 6px;
            max-width: 190px;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
            border-radius: $border-radius-base;
            position: relative;
            cursor: pointer;
        }
    
        &:not(:last-child) {
            .select__list--multiple & {
                margin-right: 8px;
            }
        }
    
        &.select__item--highlighted {
            background-color: $L-background-hover;
        }
    
        &.has-no-results {
            cursor: default;
    
            &:hover {
                .select__list:not(.select__list--single) & {
                    color: $L-text;
                    background-color: transparent;
                }
            }
        }
    
        &[data-value='placeholder'] {
            color: $L-text-medium;
            font-size: $font-size-small;
            letter-spacing: $letter-spacing-50;
    
            .select__dropdown & {
                display: none;
            }
        }
    }
    
    .select__remove {
        appearance: none;
        background: transparent;
        border: 0;
        padding: 0;
        margin: 0;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        position: absolute;
        top: 0;
        right: 0;
        width: 24px;
        height: 100%;
        opacity: .8;
        cursor: pointer;
    
        .select__list--single & {
            display: none;
        }
    }
    
    .select__search-icon {
        display: none;
        font-size: 24px;
        position: absolute;
        top: 12px;
        right: 16px;
        z-index: map-get($zindex, 'default');
    
        .select__container.is-flipped & {
            top: auto;
            bottom: 12px;
        }
    
        .select--search & {
            display: inline-block;
        }
    }
    
    .select__close-icon {
        font-size: 15px;
        pointer-events: none;
    }
    
    .select__option-span {
        font-size: $font-size-tiny;
    }
    
  • URL: /components/raw/select/select.scss
  • Filesystem Path: src/patterns/components/forms/select/select.scss
  • Size: 5 KB
  • Content:
    import Choices, { Choices as ChoicesLib } from 'choices.js';
    
    import Component from '../../component/component';
    import Icon from '../../icon/icon';
    
    import '../textfield/textfield';
    
    import './select.scss';
    
    export interface ISelectSettings {
        noResultsText: string;
        search: boolean;
        removeItemText: string;
    }
    
    export default class Select extends Component {
        static initSelector: string = '.select';
    
        public settings: ISelectSettings;
        public input: JQuery;
        public choices: Choices;
        public multiple: boolean;
    
        constructor(target: HTMLElement) {
            super(target);
    
            this.input = this.element.find('.select__input');
    
            if (this.input.length) {
                this.settings = $.extend({
                    multiselect: false,
                    noResultsText: 'No results found',
                    removeItemText: 'Remove item',
                    search: false,
                }, this.input.data());
    
                this.multiple = !!this.input.attr('multiple');
    
                this.init();
            }
        }
    
        setValue(value: string | string[]): void {
            this.choices.setChoiceByValue(value);
        }
    
        init(): void {
            this.choices = new Choices(this.input[0] as HTMLInputElement, {
                callbackOnCreateTemplates: (template: ChoicesLib.Types.strToEl): Partial<ChoicesLib.Templates> => ({
                    dropdown: (classNames: ChoicesLib.ClassNames): HTMLElement => template(`
                            <div class="${classNames.list} ${classNames.listDropdown}" aria-expanded="false">
                                ${Icon.render('search', '', 'select__search-icon')}
                            </div>
                        `) as HTMLElement,
                    item: (classNames: ChoicesLib.ClassNames, data: ChoicesLib.Choice): HTMLElement => template(`
                            <div class="${classNames.item}" data-item data-id="${data.id}" data-value="${data.value}" ${data.active ? 'aria-selected="true"' : ''} ${data.disabled ? 'aria-disabled="true"' : ''} data-deletable>
                                ${data.label}
                                <button type="button" class="${classNames.button}" aria-label="${this.settings.removeItemText}" data-button>${Icon.render('close', '', 'select__close-icon')}</button>
                            </div>
                        `) as HTMLElement,
                }),
                classNames: {
                    activeState: 'is-active',
                    button: 'select__remove',
                    containerInner: 'textfield__input select__inner',
                    containerOuter: 'select__container',
                    disabledState: 'is-disabled',
                    flippedState: 'is-flipped',
                    focusState: 'is-focused',
                    group: 'select__group',
                    groupHeading: 'select__group-heading',
                    highlightedState: 'select__item--highlighted',
                    input: 'select__choices-input',
                    inputCloned: 'select__choices-input--cloned',
                    item: 'select__item',
                    itemChoice: 'select__item--choice',
                    itemDisabled: 'select__item--disabled',
                    itemSelectable: 'select__item--selectable',
                    list: 'select__list',
                    listDropdown: 'select__dropdown',
                    listItems: 'select__list--multiple',
                    listSingle: 'select__list--single',
                    loadingState: 'is-loading',
                    noChoices: 'has-no-choices',
                    noResults: 'has-no-results',
                    openState: 'is-open',
                    placeholder: 'select__placeholder',
                    selectedState: 'is-selected',
                },
                editItems: false,
                itemSelectText: '',
                noResultsText: this.settings.noResultsText,
                removeItemButton: true,
                removeItems: true,
                renderSelectedChoices: 'always',
                searchChoices: this.settings.search,
                searchEnabled: this.settings.search,
            });
    
            this.addEventListeners();
        }
    
        addEventListeners(): void {
            // Multiselect context
            if (this.multiple) {
                // Deselect a selected item when clicking on it.
                this.input[0].addEventListener('choice', (event: CustomEvent) => {
                    const values: string[] | string = this.choices.getValue(true);
                    const value: string = event.detail.choice.value;
    
                    if (values?.includes(value)) {
                        setTimeout((): Choices => this.choices.removeActiveItemsByValue(value));
                    }
                });
    
                // Close dropdown when clicking on empty space between currently selected items in select list.
                this.element.find('.select__inner > .select__list').on('click', (): void => {
                    this.choices.hideDropdown();
                });
            }
    
            this.input[0].addEventListener('setValue', (event: CustomEvent): void => {
                const values: string | string[] = event.detail;
    
                if (typeof values !== 'undefined') {
                    this.setValue(event.detail);
                }
            });
    
            this.input[0].addEventListener('hideDropdown', (): void => {
                this.choices.hideDropdown();
    
                // Clear search input when closing dropdown
                if (this.settings.search) {
                    this.choices.clearInput();
                }
            });
    
            this.input[0].addEventListener('showDropdown', (): void => {
                // Focus search input when opening dropdown if search enabled.
                if (this.settings.search) {
                    this.element.find('.select__dropdown .select__choices-input--cloned').trigger('focus');
                }
    
                this.choices.showDropdown();
            });
        }
    }
    
  • URL: /components/raw/select/select.ts
  • Filesystem Path: src/patterns/components/forms/select/select.ts
  • Size: 5.8 KB

Placeholder

Used to display a placeholder text and force the user to make a selection

<div class="textfield select ">
    <label class="textfield__label select__label  " for="select1">
        Select label
    </label>
    <div class="textfield__inner">
        <select name="select" id="select1" class="textfield__input select__input">
            <option value="placeholder" disabled selected>
                Placeholder
            </option>
            <option value="1">
                Lorem ipsum dolor sit amet, consectetur adipisicing elit. Veritatis error velit quidem alias nihil mollitia temporibus, maxime dicta repellat. Perspiciatis veniam doloribus, quia corporis commodi sed omnis adipisci facilis nisi.
            </option>
            <option value="2">
                Option 2
            </option>
            <option value="3">
                Option 3
            </option>
        </select>
        <svg class="icon  select__icon" focusable="false">
            <use href="../../inc/svg/global.4609ec92109fc41e7ad4764ef897ea8e.svg#"></use>
        </svg>

    </div>
</div>
{% set input %}
    <select
        name="{{ data.name }}"
        id="{{ data.id }}"
        {% if 'select--multiple' in modifier %} multiple{% endif %}
        {% if 'select--search' in modifier %} data-search="true"{% endif %}
        class="textfield__input select__input"
        {% if data.isDisabled %} disabled{% endif %}
        {% if 'select--search' in modifier %} data-no-results-text="{{ data.noResultsText }}"{% endif %}
        {% if 'select--multiple' in modifier %} data-remove-item-text="{{ data.removeItemText }}"{% endif %}
        {{ data.attributes }}
    >
        {% if data.placeholder or data.hasPlaceholder %}
            <option value="placeholder" disabled selected>
                {% if data.placeholder %}
                    {{ data.placeholder }}
                {% endif %}
            </option>
        {% endif %}
        {% for option in data.options %}
            <option
                value="{{ option.value }}"
                {% if option.isSelected %} selected {% endif %}
            >
                {{ option.name }}
            </option>
        {% endfor %}
    </select>
    {% include '@icon' with { class: 'select__icon', modifier: '', name: data.iconName } %}
{% endset %}

{% include '@textfield' with {
    data: data,
    input: input,
    class: 'select ' ~ class,
    modifier: modifier,
    labelClass: 'select__label' ~ ' ' ~ labelClass
} %}
{
  "language": "en-US",
  "data": {
    "label": "Select label",
    "id": "select1",
    "name": "select",
    "options": [
      {
        "name": "Lorem ipsum dolor sit amet, consectetur adipisicing elit. Veritatis error velit quidem alias nihil mollitia temporibus, maxime dicta repellat. Perspiciatis veniam doloribus, quia corporis commodi sed omnis adipisci facilis nisi.",
        "value": "1"
      },
      {
        "name": "Option 2",
        "value": "2"
      },
      {
        "name": "Option 3",
        "value": "3"
      }
    ],
    "placeholder": "Placeholder"
  }
}
  • Content:
    .select {
        position: relative;
        margin: 0;
        cursor: pointer;
    
        &.is-disabled {
            cursor: default;
        }
    }
    
    .select__icon {
        position: absolute;
        top: 50%;
        right: 16px;
        transform: translateY(-50%);
        font-size: 24px;
        pointer-events: none;
    
        .select__container.is-open + & {
            transform: translateY(-50%) rotate(180deg);
        }
    }
    
    .select__inner {
        padding-right: calc(24px + 4px);
        min-height: 32px;
        height: auto;
        box-shadow: $elevation-01;
        display: flex;
        align-items: center;
    
        .select__container.is-focused & {
            border-color: $L-border-focus;
        }
    }
    
    .select__dropdown {
        visibility: hidden;
        z-index: 2;
        position: absolute;
        top: 100%;
        width: 100%;
        background-color: $L-background-weak;
        border: none;
        overflow: hidden;
        word-break: break-all; /* stylelint-disable-line plugin/no-unsupported-browser-features */
        will-change: visibility;
        border-radius: $border-radius-base;
        box-shadow: $elevation-02;
    
        .select--search & {
            padding-top: 48px;
        }
    
        .select__container.is-flipped & {
            top: auto;
            bottom: 100%;
    
            .select--search & {
                padding-top: 0;
                padding-bottom: 48px;
            }
        }
    
        .select__container.is-open & {
            visibility: visible;
        }
    }
    
    .select__choices-input {
        background: transparent;
        border: none;
        appearance: none;
        height: 48px;
        display: none;
        width: 100% !important; /* overwrite plugin inline styles */
        padding: 10px 16px;
        z-index: -1;
        pointer-events: none;
        position: absolute;
        top: 100%;
        left: 0;
    
        .select__container.is-flipped & {
            top: auto;
            bottom: 100%;
        }
    
        .select--multiple:not(.select--search) & {
            color: transparent;
            outline: none;
        }
    
        .select--search .select__container.is-open & {
            pointer-events: auto;
        }
    
        &:not(select) {
            display: block;
            z-index: 3;
        }
    
        &::-ms-expand {
            display: none;
        }
    }
    
    .select__list {
        .select__dropdown & {
            padding: 8px 0;
            max-height: 220px;
            overflow-y: auto;
            will-change: scroll-position;
    
            .select--search & {
                border-top: 1px solid $L-border;
            }
    
            .select__container.is-flipped & {
                .select--search & {
                    border-top: 0;
                    border-bottom: 1px solid $L-border;
                }
            }
        }
    }
    
    .select__list--single,
    .select__list--multiple {
        overflow: hidden;
        white-space: nowrap;
        padding: 4px 0;
        width: 100%;
        height: 100%;
    }
    
    .select__list--multiple {
        overflow: visible;
        white-space: normal;
        padding: 10px 0 4px;
        line-height: 0;
    }
    
    .select__item {
        padding: 8px 16px;
        color: $L-text-black;
        font-size: $font-size-small;
        line-height: $line-height-base;
    
        .select__list--single & {
            padding: 0;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
            color: $L-text;
        }
    
        .select__list--multiple & {
            display: inline-block;
            background-color: $L-background-medium;
            font-size: 12px;
            padding: 2px 24px 2px 8px;
            margin-bottom: 6px;
            max-width: 190px;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
            border-radius: $border-radius-base;
            position: relative;
            cursor: pointer;
        }
    
        &:not(:last-child) {
            .select__list--multiple & {
                margin-right: 8px;
            }
        }
    
        &.select__item--highlighted {
            background-color: $L-background-hover;
        }
    
        &.has-no-results {
            cursor: default;
    
            &:hover {
                .select__list:not(.select__list--single) & {
                    color: $L-text;
                    background-color: transparent;
                }
            }
        }
    
        &[data-value='placeholder'] {
            color: $L-text-medium;
            font-size: $font-size-small;
            letter-spacing: $letter-spacing-50;
    
            .select__dropdown & {
                display: none;
            }
        }
    }
    
    .select__remove {
        appearance: none;
        background: transparent;
        border: 0;
        padding: 0;
        margin: 0;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        position: absolute;
        top: 0;
        right: 0;
        width: 24px;
        height: 100%;
        opacity: .8;
        cursor: pointer;
    
        .select__list--single & {
            display: none;
        }
    }
    
    .select__search-icon {
        display: none;
        font-size: 24px;
        position: absolute;
        top: 12px;
        right: 16px;
        z-index: map-get($zindex, 'default');
    
        .select__container.is-flipped & {
            top: auto;
            bottom: 12px;
        }
    
        .select--search & {
            display: inline-block;
        }
    }
    
    .select__close-icon {
        font-size: 15px;
        pointer-events: none;
    }
    
    .select__option-span {
        font-size: $font-size-tiny;
    }
    
  • URL: /components/raw/select/select.scss
  • Filesystem Path: src/patterns/components/forms/select/select.scss
  • Size: 5 KB
  • Content:
    import Choices, { Choices as ChoicesLib } from 'choices.js';
    
    import Component from '../../component/component';
    import Icon from '../../icon/icon';
    
    import '../textfield/textfield';
    
    import './select.scss';
    
    export interface ISelectSettings {
        noResultsText: string;
        search: boolean;
        removeItemText: string;
    }
    
    export default class Select extends Component {
        static initSelector: string = '.select';
    
        public settings: ISelectSettings;
        public input: JQuery;
        public choices: Choices;
        public multiple: boolean;
    
        constructor(target: HTMLElement) {
            super(target);
    
            this.input = this.element.find('.select__input');
    
            if (this.input.length) {
                this.settings = $.extend({
                    multiselect: false,
                    noResultsText: 'No results found',
                    removeItemText: 'Remove item',
                    search: false,
                }, this.input.data());
    
                this.multiple = !!this.input.attr('multiple');
    
                this.init();
            }
        }
    
        setValue(value: string | string[]): void {
            this.choices.setChoiceByValue(value);
        }
    
        init(): void {
            this.choices = new Choices(this.input[0] as HTMLInputElement, {
                callbackOnCreateTemplates: (template: ChoicesLib.Types.strToEl): Partial<ChoicesLib.Templates> => ({
                    dropdown: (classNames: ChoicesLib.ClassNames): HTMLElement => template(`
                            <div class="${classNames.list} ${classNames.listDropdown}" aria-expanded="false">
                                ${Icon.render('search', '', 'select__search-icon')}
                            </div>
                        `) as HTMLElement,
                    item: (classNames: ChoicesLib.ClassNames, data: ChoicesLib.Choice): HTMLElement => template(`
                            <div class="${classNames.item}" data-item data-id="${data.id}" data-value="${data.value}" ${data.active ? 'aria-selected="true"' : ''} ${data.disabled ? 'aria-disabled="true"' : ''} data-deletable>
                                ${data.label}
                                <button type="button" class="${classNames.button}" aria-label="${this.settings.removeItemText}" data-button>${Icon.render('close', '', 'select__close-icon')}</button>
                            </div>
                        `) as HTMLElement,
                }),
                classNames: {
                    activeState: 'is-active',
                    button: 'select__remove',
                    containerInner: 'textfield__input select__inner',
                    containerOuter: 'select__container',
                    disabledState: 'is-disabled',
                    flippedState: 'is-flipped',
                    focusState: 'is-focused',
                    group: 'select__group',
                    groupHeading: 'select__group-heading',
                    highlightedState: 'select__item--highlighted',
                    input: 'select__choices-input',
                    inputCloned: 'select__choices-input--cloned',
                    item: 'select__item',
                    itemChoice: 'select__item--choice',
                    itemDisabled: 'select__item--disabled',
                    itemSelectable: 'select__item--selectable',
                    list: 'select__list',
                    listDropdown: 'select__dropdown',
                    listItems: 'select__list--multiple',
                    listSingle: 'select__list--single',
                    loadingState: 'is-loading',
                    noChoices: 'has-no-choices',
                    noResults: 'has-no-results',
                    openState: 'is-open',
                    placeholder: 'select__placeholder',
                    selectedState: 'is-selected',
                },
                editItems: false,
                itemSelectText: '',
                noResultsText: this.settings.noResultsText,
                removeItemButton: true,
                removeItems: true,
                renderSelectedChoices: 'always',
                searchChoices: this.settings.search,
                searchEnabled: this.settings.search,
            });
    
            this.addEventListeners();
        }
    
        addEventListeners(): void {
            // Multiselect context
            if (this.multiple) {
                // Deselect a selected item when clicking on it.
                this.input[0].addEventListener('choice', (event: CustomEvent) => {
                    const values: string[] | string = this.choices.getValue(true);
                    const value: string = event.detail.choice.value;
    
                    if (values?.includes(value)) {
                        setTimeout((): Choices => this.choices.removeActiveItemsByValue(value));
                    }
                });
    
                // Close dropdown when clicking on empty space between currently selected items in select list.
                this.element.find('.select__inner > .select__list').on('click', (): void => {
                    this.choices.hideDropdown();
                });
            }
    
            this.input[0].addEventListener('setValue', (event: CustomEvent): void => {
                const values: string | string[] = event.detail;
    
                if (typeof values !== 'undefined') {
                    this.setValue(event.detail);
                }
            });
    
            this.input[0].addEventListener('hideDropdown', (): void => {
                this.choices.hideDropdown();
    
                // Clear search input when closing dropdown
                if (this.settings.search) {
                    this.choices.clearInput();
                }
            });
    
            this.input[0].addEventListener('showDropdown', (): void => {
                // Focus search input when opening dropdown if search enabled.
                if (this.settings.search) {
                    this.element.find('.select__dropdown .select__choices-input--cloned').trigger('focus');
                }
    
                this.choices.showDropdown();
            });
        }
    }
    
  • URL: /components/raw/select/select.ts
  • Filesystem Path: src/patterns/components/forms/select/select.ts
  • Size: 5.8 KB
  • Handle: @select--placeholder
  • Filesystem Path: src/patterns/components/forms/select/select.twig
  • References (2): @icon, @textfield

Empty Placeholder

Used to display an empty select and force the user to make a selection

<div class="textfield select ">
    <label class="textfield__label select__label  " for="select1">
        Select label
    </label>
    <div class="textfield__inner">
        <select name="select" id="select1" class="textfield__input select__input">
            <option value="placeholder" disabled selected>
            </option>
            <option value="1">
                Lorem ipsum dolor sit amet, consectetur adipisicing elit. Veritatis error velit quidem alias nihil mollitia temporibus, maxime dicta repellat. Perspiciatis veniam doloribus, quia corporis commodi sed omnis adipisci facilis nisi.
            </option>
            <option value="2">
                Option 2
            </option>
            <option value="3">
                Option 3
            </option>
        </select>
        <svg class="icon  select__icon" focusable="false">
            <use href="../../inc/svg/global.4609ec92109fc41e7ad4764ef897ea8e.svg#"></use>
        </svg>

    </div>
</div>
{% set input %}
    <select
        name="{{ data.name }}"
        id="{{ data.id }}"
        {% if 'select--multiple' in modifier %} multiple{% endif %}
        {% if 'select--search' in modifier %} data-search="true"{% endif %}
        class="textfield__input select__input"
        {% if data.isDisabled %} disabled{% endif %}
        {% if 'select--search' in modifier %} data-no-results-text="{{ data.noResultsText }}"{% endif %}
        {% if 'select--multiple' in modifier %} data-remove-item-text="{{ data.removeItemText }}"{% endif %}
        {{ data.attributes }}
    >
        {% if data.placeholder or data.hasPlaceholder %}
            <option value="placeholder" disabled selected>
                {% if data.placeholder %}
                    {{ data.placeholder }}
                {% endif %}
            </option>
        {% endif %}
        {% for option in data.options %}
            <option
                value="{{ option.value }}"
                {% if option.isSelected %} selected {% endif %}
            >
                {{ option.name }}
            </option>
        {% endfor %}
    </select>
    {% include '@icon' with { class: 'select__icon', modifier: '', name: data.iconName } %}
{% endset %}

{% include '@textfield' with {
    data: data,
    input: input,
    class: 'select ' ~ class,
    modifier: modifier,
    labelClass: 'select__label' ~ ' ' ~ labelClass
} %}
{
  "language": "en-US",
  "data": {
    "label": "Select label",
    "id": "select1",
    "name": "select",
    "options": [
      {
        "name": "Lorem ipsum dolor sit amet, consectetur adipisicing elit. Veritatis error velit quidem alias nihil mollitia temporibus, maxime dicta repellat. Perspiciatis veniam doloribus, quia corporis commodi sed omnis adipisci facilis nisi.",
        "value": "1"
      },
      {
        "name": "Option 2",
        "value": "2"
      },
      {
        "name": "Option 3",
        "value": "3"
      }
    ],
    "hasPlaceholder": true
  }
}
  • Content:
    .select {
        position: relative;
        margin: 0;
        cursor: pointer;
    
        &.is-disabled {
            cursor: default;
        }
    }
    
    .select__icon {
        position: absolute;
        top: 50%;
        right: 16px;
        transform: translateY(-50%);
        font-size: 24px;
        pointer-events: none;
    
        .select__container.is-open + & {
            transform: translateY(-50%) rotate(180deg);
        }
    }
    
    .select__inner {
        padding-right: calc(24px + 4px);
        min-height: 32px;
        height: auto;
        box-shadow: $elevation-01;
        display: flex;
        align-items: center;
    
        .select__container.is-focused & {
            border-color: $L-border-focus;
        }
    }
    
    .select__dropdown {
        visibility: hidden;
        z-index: 2;
        position: absolute;
        top: 100%;
        width: 100%;
        background-color: $L-background-weak;
        border: none;
        overflow: hidden;
        word-break: break-all; /* stylelint-disable-line plugin/no-unsupported-browser-features */
        will-change: visibility;
        border-radius: $border-radius-base;
        box-shadow: $elevation-02;
    
        .select--search & {
            padding-top: 48px;
        }
    
        .select__container.is-flipped & {
            top: auto;
            bottom: 100%;
    
            .select--search & {
                padding-top: 0;
                padding-bottom: 48px;
            }
        }
    
        .select__container.is-open & {
            visibility: visible;
        }
    }
    
    .select__choices-input {
        background: transparent;
        border: none;
        appearance: none;
        height: 48px;
        display: none;
        width: 100% !important; /* overwrite plugin inline styles */
        padding: 10px 16px;
        z-index: -1;
        pointer-events: none;
        position: absolute;
        top: 100%;
        left: 0;
    
        .select__container.is-flipped & {
            top: auto;
            bottom: 100%;
        }
    
        .select--multiple:not(.select--search) & {
            color: transparent;
            outline: none;
        }
    
        .select--search .select__container.is-open & {
            pointer-events: auto;
        }
    
        &:not(select) {
            display: block;
            z-index: 3;
        }
    
        &::-ms-expand {
            display: none;
        }
    }
    
    .select__list {
        .select__dropdown & {
            padding: 8px 0;
            max-height: 220px;
            overflow-y: auto;
            will-change: scroll-position;
    
            .select--search & {
                border-top: 1px solid $L-border;
            }
    
            .select__container.is-flipped & {
                .select--search & {
                    border-top: 0;
                    border-bottom: 1px solid $L-border;
                }
            }
        }
    }
    
    .select__list--single,
    .select__list--multiple {
        overflow: hidden;
        white-space: nowrap;
        padding: 4px 0;
        width: 100%;
        height: 100%;
    }
    
    .select__list--multiple {
        overflow: visible;
        white-space: normal;
        padding: 10px 0 4px;
        line-height: 0;
    }
    
    .select__item {
        padding: 8px 16px;
        color: $L-text-black;
        font-size: $font-size-small;
        line-height: $line-height-base;
    
        .select__list--single & {
            padding: 0;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
            color: $L-text;
        }
    
        .select__list--multiple & {
            display: inline-block;
            background-color: $L-background-medium;
            font-size: 12px;
            padding: 2px 24px 2px 8px;
            margin-bottom: 6px;
            max-width: 190px;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
            border-radius: $border-radius-base;
            position: relative;
            cursor: pointer;
        }
    
        &:not(:last-child) {
            .select__list--multiple & {
                margin-right: 8px;
            }
        }
    
        &.select__item--highlighted {
            background-color: $L-background-hover;
        }
    
        &.has-no-results {
            cursor: default;
    
            &:hover {
                .select__list:not(.select__list--single) & {
                    color: $L-text;
                    background-color: transparent;
                }
            }
        }
    
        &[data-value='placeholder'] {
            color: $L-text-medium;
            font-size: $font-size-small;
            letter-spacing: $letter-spacing-50;
    
            .select__dropdown & {
                display: none;
            }
        }
    }
    
    .select__remove {
        appearance: none;
        background: transparent;
        border: 0;
        padding: 0;
        margin: 0;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        position: absolute;
        top: 0;
        right: 0;
        width: 24px;
        height: 100%;
        opacity: .8;
        cursor: pointer;
    
        .select__list--single & {
            display: none;
        }
    }
    
    .select__search-icon {
        display: none;
        font-size: 24px;
        position: absolute;
        top: 12px;
        right: 16px;
        z-index: map-get($zindex, 'default');
    
        .select__container.is-flipped & {
            top: auto;
            bottom: 12px;
        }
    
        .select--search & {
            display: inline-block;
        }
    }
    
    .select__close-icon {
        font-size: 15px;
        pointer-events: none;
    }
    
    .select__option-span {
        font-size: $font-size-tiny;
    }
    
  • URL: /components/raw/select/select.scss
  • Filesystem Path: src/patterns/components/forms/select/select.scss
  • Size: 5 KB
  • Content:
    import Choices, { Choices as ChoicesLib } from 'choices.js';
    
    import Component from '../../component/component';
    import Icon from '../../icon/icon';
    
    import '../textfield/textfield';
    
    import './select.scss';
    
    export interface ISelectSettings {
        noResultsText: string;
        search: boolean;
        removeItemText: string;
    }
    
    export default class Select extends Component {
        static initSelector: string = '.select';
    
        public settings: ISelectSettings;
        public input: JQuery;
        public choices: Choices;
        public multiple: boolean;
    
        constructor(target: HTMLElement) {
            super(target);
    
            this.input = this.element.find('.select__input');
    
            if (this.input.length) {
                this.settings = $.extend({
                    multiselect: false,
                    noResultsText: 'No results found',
                    removeItemText: 'Remove item',
                    search: false,
                }, this.input.data());
    
                this.multiple = !!this.input.attr('multiple');
    
                this.init();
            }
        }
    
        setValue(value: string | string[]): void {
            this.choices.setChoiceByValue(value);
        }
    
        init(): void {
            this.choices = new Choices(this.input[0] as HTMLInputElement, {
                callbackOnCreateTemplates: (template: ChoicesLib.Types.strToEl): Partial<ChoicesLib.Templates> => ({
                    dropdown: (classNames: ChoicesLib.ClassNames): HTMLElement => template(`
                            <div class="${classNames.list} ${classNames.listDropdown}" aria-expanded="false">
                                ${Icon.render('search', '', 'select__search-icon')}
                            </div>
                        `) as HTMLElement,
                    item: (classNames: ChoicesLib.ClassNames, data: ChoicesLib.Choice): HTMLElement => template(`
                            <div class="${classNames.item}" data-item data-id="${data.id}" data-value="${data.value}" ${data.active ? 'aria-selected="true"' : ''} ${data.disabled ? 'aria-disabled="true"' : ''} data-deletable>
                                ${data.label}
                                <button type="button" class="${classNames.button}" aria-label="${this.settings.removeItemText}" data-button>${Icon.render('close', '', 'select__close-icon')}</button>
                            </div>
                        `) as HTMLElement,
                }),
                classNames: {
                    activeState: 'is-active',
                    button: 'select__remove',
                    containerInner: 'textfield__input select__inner',
                    containerOuter: 'select__container',
                    disabledState: 'is-disabled',
                    flippedState: 'is-flipped',
                    focusState: 'is-focused',
                    group: 'select__group',
                    groupHeading: 'select__group-heading',
                    highlightedState: 'select__item--highlighted',
                    input: 'select__choices-input',
                    inputCloned: 'select__choices-input--cloned',
                    item: 'select__item',
                    itemChoice: 'select__item--choice',
                    itemDisabled: 'select__item--disabled',
                    itemSelectable: 'select__item--selectable',
                    list: 'select__list',
                    listDropdown: 'select__dropdown',
                    listItems: 'select__list--multiple',
                    listSingle: 'select__list--single',
                    loadingState: 'is-loading',
                    noChoices: 'has-no-choices',
                    noResults: 'has-no-results',
                    openState: 'is-open',
                    placeholder: 'select__placeholder',
                    selectedState: 'is-selected',
                },
                editItems: false,
                itemSelectText: '',
                noResultsText: this.settings.noResultsText,
                removeItemButton: true,
                removeItems: true,
                renderSelectedChoices: 'always',
                searchChoices: this.settings.search,
                searchEnabled: this.settings.search,
            });
    
            this.addEventListeners();
        }
    
        addEventListeners(): void {
            // Multiselect context
            if (this.multiple) {
                // Deselect a selected item when clicking on it.
                this.input[0].addEventListener('choice', (event: CustomEvent) => {
                    const values: string[] | string = this.choices.getValue(true);
                    const value: string = event.detail.choice.value;
    
                    if (values?.includes(value)) {
                        setTimeout((): Choices => this.choices.removeActiveItemsByValue(value));
                    }
                });
    
                // Close dropdown when clicking on empty space between currently selected items in select list.
                this.element.find('.select__inner > .select__list').on('click', (): void => {
                    this.choices.hideDropdown();
                });
            }
    
            this.input[0].addEventListener('setValue', (event: CustomEvent): void => {
                const values: string | string[] = event.detail;
    
                if (typeof values !== 'undefined') {
                    this.setValue(event.detail);
                }
            });
    
            this.input[0].addEventListener('hideDropdown', (): void => {
                this.choices.hideDropdown();
    
                // Clear search input when closing dropdown
                if (this.settings.search) {
                    this.choices.clearInput();
                }
            });
    
            this.input[0].addEventListener('showDropdown', (): void => {
                // Focus search input when opening dropdown if search enabled.
                if (this.settings.search) {
                    this.element.find('.select__dropdown .select__choices-input--cloned').trigger('focus');
                }
    
                this.choices.showDropdown();
            });
        }
    }
    
  • URL: /components/raw/select/select.ts
  • Filesystem Path: src/patterns/components/forms/select/select.ts
  • Size: 5.8 KB
  • Handle: @select--empty-placeholder
  • Filesystem Path: src/patterns/components/forms/select/select.twig
  • References (2): @icon, @textfield

Multiple

<div class="textfield select--multiple select ">
    <label class="textfield__label select__label  " for="select1">
        Select label
    </label>
    <div class="textfield__inner">
        <select name="select" id="select1" multiple class="textfield__input select__input" data-remove-item-text="Remove item">
            <option value="1">
                Lorem ipsum dolor sit amet, consectetur adipisicing elit. Veritatis error velit quidem alias nihil mollitia temporibus, maxime dicta repellat. Perspiciatis veniam doloribus, quia corporis commodi sed omnis adipisci facilis nisi.
            </option>
            <option value="2">
                Option 2
            </option>
            <option value="3">
                Option 3
            </option>
            <option value="4">
                Option 4
            </option>
            <option value="5">
                Option 5
            </option>
        </select>
        <svg class="icon  select__icon" focusable="false">
            <use href="../../inc/svg/global.4609ec92109fc41e7ad4764ef897ea8e.svg#"></use>
        </svg>

    </div>
</div>
{% set input %}
    <select
        name="{{ data.name }}"
        id="{{ data.id }}"
        {% if 'select--multiple' in modifier %} multiple{% endif %}
        {% if 'select--search' in modifier %} data-search="true"{% endif %}
        class="textfield__input select__input"
        {% if data.isDisabled %} disabled{% endif %}
        {% if 'select--search' in modifier %} data-no-results-text="{{ data.noResultsText }}"{% endif %}
        {% if 'select--multiple' in modifier %} data-remove-item-text="{{ data.removeItemText }}"{% endif %}
        {{ data.attributes }}
    >
        {% if data.placeholder or data.hasPlaceholder %}
            <option value="placeholder" disabled selected>
                {% if data.placeholder %}
                    {{ data.placeholder }}
                {% endif %}
            </option>
        {% endif %}
        {% for option in data.options %}
            <option
                value="{{ option.value }}"
                {% if option.isSelected %} selected {% endif %}
            >
                {{ option.name }}
            </option>
        {% endfor %}
    </select>
    {% include '@icon' with { class: 'select__icon', modifier: '', name: data.iconName } %}
{% endset %}

{% include '@textfield' with {
    data: data,
    input: input,
    class: 'select ' ~ class,
    modifier: modifier,
    labelClass: 'select__label' ~ ' ' ~ labelClass
} %}
{
  "language": "en-US",
  "data": {
    "label": "Select label",
    "id": "select1",
    "name": "select",
    "options": [
      {
        "name": "Lorem ipsum dolor sit amet, consectetur adipisicing elit. Veritatis error velit quidem alias nihil mollitia temporibus, maxime dicta repellat. Perspiciatis veniam doloribus, quia corporis commodi sed omnis adipisci facilis nisi.",
        "value": "1"
      },
      {
        "name": "Option 2",
        "value": "2"
      },
      {
        "name": "Option 3",
        "value": "3"
      },
      {
        "name": "Option 4",
        "value": "4"
      },
      {
        "name": "Option 5",
        "value": "5"
      }
    ],
    "removeItemText": "Remove item"
  },
  "modifier": "select--multiple"
}
  • Content:
    .select {
        position: relative;
        margin: 0;
        cursor: pointer;
    
        &.is-disabled {
            cursor: default;
        }
    }
    
    .select__icon {
        position: absolute;
        top: 50%;
        right: 16px;
        transform: translateY(-50%);
        font-size: 24px;
        pointer-events: none;
    
        .select__container.is-open + & {
            transform: translateY(-50%) rotate(180deg);
        }
    }
    
    .select__inner {
        padding-right: calc(24px + 4px);
        min-height: 32px;
        height: auto;
        box-shadow: $elevation-01;
        display: flex;
        align-items: center;
    
        .select__container.is-focused & {
            border-color: $L-border-focus;
        }
    }
    
    .select__dropdown {
        visibility: hidden;
        z-index: 2;
        position: absolute;
        top: 100%;
        width: 100%;
        background-color: $L-background-weak;
        border: none;
        overflow: hidden;
        word-break: break-all; /* stylelint-disable-line plugin/no-unsupported-browser-features */
        will-change: visibility;
        border-radius: $border-radius-base;
        box-shadow: $elevation-02;
    
        .select--search & {
            padding-top: 48px;
        }
    
        .select__container.is-flipped & {
            top: auto;
            bottom: 100%;
    
            .select--search & {
                padding-top: 0;
                padding-bottom: 48px;
            }
        }
    
        .select__container.is-open & {
            visibility: visible;
        }
    }
    
    .select__choices-input {
        background: transparent;
        border: none;
        appearance: none;
        height: 48px;
        display: none;
        width: 100% !important; /* overwrite plugin inline styles */
        padding: 10px 16px;
        z-index: -1;
        pointer-events: none;
        position: absolute;
        top: 100%;
        left: 0;
    
        .select__container.is-flipped & {
            top: auto;
            bottom: 100%;
        }
    
        .select--multiple:not(.select--search) & {
            color: transparent;
            outline: none;
        }
    
        .select--search .select__container.is-open & {
            pointer-events: auto;
        }
    
        &:not(select) {
            display: block;
            z-index: 3;
        }
    
        &::-ms-expand {
            display: none;
        }
    }
    
    .select__list {
        .select__dropdown & {
            padding: 8px 0;
            max-height: 220px;
            overflow-y: auto;
            will-change: scroll-position;
    
            .select--search & {
                border-top: 1px solid $L-border;
            }
    
            .select__container.is-flipped & {
                .select--search & {
                    border-top: 0;
                    border-bottom: 1px solid $L-border;
                }
            }
        }
    }
    
    .select__list--single,
    .select__list--multiple {
        overflow: hidden;
        white-space: nowrap;
        padding: 4px 0;
        width: 100%;
        height: 100%;
    }
    
    .select__list--multiple {
        overflow: visible;
        white-space: normal;
        padding: 10px 0 4px;
        line-height: 0;
    }
    
    .select__item {
        padding: 8px 16px;
        color: $L-text-black;
        font-size: $font-size-small;
        line-height: $line-height-base;
    
        .select__list--single & {
            padding: 0;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
            color: $L-text;
        }
    
        .select__list--multiple & {
            display: inline-block;
            background-color: $L-background-medium;
            font-size: 12px;
            padding: 2px 24px 2px 8px;
            margin-bottom: 6px;
            max-width: 190px;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
            border-radius: $border-radius-base;
            position: relative;
            cursor: pointer;
        }
    
        &:not(:last-child) {
            .select__list--multiple & {
                margin-right: 8px;
            }
        }
    
        &.select__item--highlighted {
            background-color: $L-background-hover;
        }
    
        &.has-no-results {
            cursor: default;
    
            &:hover {
                .select__list:not(.select__list--single) & {
                    color: $L-text;
                    background-color: transparent;
                }
            }
        }
    
        &[data-value='placeholder'] {
            color: $L-text-medium;
            font-size: $font-size-small;
            letter-spacing: $letter-spacing-50;
    
            .select__dropdown & {
                display: none;
            }
        }
    }
    
    .select__remove {
        appearance: none;
        background: transparent;
        border: 0;
        padding: 0;
        margin: 0;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        position: absolute;
        top: 0;
        right: 0;
        width: 24px;
        height: 100%;
        opacity: .8;
        cursor: pointer;
    
        .select__list--single & {
            display: none;
        }
    }
    
    .select__search-icon {
        display: none;
        font-size: 24px;
        position: absolute;
        top: 12px;
        right: 16px;
        z-index: map-get($zindex, 'default');
    
        .select__container.is-flipped & {
            top: auto;
            bottom: 12px;
        }
    
        .select--search & {
            display: inline-block;
        }
    }
    
    .select__close-icon {
        font-size: 15px;
        pointer-events: none;
    }
    
    .select__option-span {
        font-size: $font-size-tiny;
    }
    
  • URL: /components/raw/select/select.scss
  • Filesystem Path: src/patterns/components/forms/select/select.scss
  • Size: 5 KB
  • Content:
    import Choices, { Choices as ChoicesLib } from 'choices.js';
    
    import Component from '../../component/component';
    import Icon from '../../icon/icon';
    
    import '../textfield/textfield';
    
    import './select.scss';
    
    export interface ISelectSettings {
        noResultsText: string;
        search: boolean;
        removeItemText: string;
    }
    
    export default class Select extends Component {
        static initSelector: string = '.select';
    
        public settings: ISelectSettings;
        public input: JQuery;
        public choices: Choices;
        public multiple: boolean;
    
        constructor(target: HTMLElement) {
            super(target);
    
            this.input = this.element.find('.select__input');
    
            if (this.input.length) {
                this.settings = $.extend({
                    multiselect: false,
                    noResultsText: 'No results found',
                    removeItemText: 'Remove item',
                    search: false,
                }, this.input.data());
    
                this.multiple = !!this.input.attr('multiple');
    
                this.init();
            }
        }
    
        setValue(value: string | string[]): void {
            this.choices.setChoiceByValue(value);
        }
    
        init(): void {
            this.choices = new Choices(this.input[0] as HTMLInputElement, {
                callbackOnCreateTemplates: (template: ChoicesLib.Types.strToEl): Partial<ChoicesLib.Templates> => ({
                    dropdown: (classNames: ChoicesLib.ClassNames): HTMLElement => template(`
                            <div class="${classNames.list} ${classNames.listDropdown}" aria-expanded="false">
                                ${Icon.render('search', '', 'select__search-icon')}
                            </div>
                        `) as HTMLElement,
                    item: (classNames: ChoicesLib.ClassNames, data: ChoicesLib.Choice): HTMLElement => template(`
                            <div class="${classNames.item}" data-item data-id="${data.id}" data-value="${data.value}" ${data.active ? 'aria-selected="true"' : ''} ${data.disabled ? 'aria-disabled="true"' : ''} data-deletable>
                                ${data.label}
                                <button type="button" class="${classNames.button}" aria-label="${this.settings.removeItemText}" data-button>${Icon.render('close', '', 'select__close-icon')}</button>
                            </div>
                        `) as HTMLElement,
                }),
                classNames: {
                    activeState: 'is-active',
                    button: 'select__remove',
                    containerInner: 'textfield__input select__inner',
                    containerOuter: 'select__container',
                    disabledState: 'is-disabled',
                    flippedState: 'is-flipped',
                    focusState: 'is-focused',
                    group: 'select__group',
                    groupHeading: 'select__group-heading',
                    highlightedState: 'select__item--highlighted',
                    input: 'select__choices-input',
                    inputCloned: 'select__choices-input--cloned',
                    item: 'select__item',
                    itemChoice: 'select__item--choice',
                    itemDisabled: 'select__item--disabled',
                    itemSelectable: 'select__item--selectable',
                    list: 'select__list',
                    listDropdown: 'select__dropdown',
                    listItems: 'select__list--multiple',
                    listSingle: 'select__list--single',
                    loadingState: 'is-loading',
                    noChoices: 'has-no-choices',
                    noResults: 'has-no-results',
                    openState: 'is-open',
                    placeholder: 'select__placeholder',
                    selectedState: 'is-selected',
                },
                editItems: false,
                itemSelectText: '',
                noResultsText: this.settings.noResultsText,
                removeItemButton: true,
                removeItems: true,
                renderSelectedChoices: 'always',
                searchChoices: this.settings.search,
                searchEnabled: this.settings.search,
            });
    
            this.addEventListeners();
        }
    
        addEventListeners(): void {
            // Multiselect context
            if (this.multiple) {
                // Deselect a selected item when clicking on it.
                this.input[0].addEventListener('choice', (event: CustomEvent) => {
                    const values: string[] | string = this.choices.getValue(true);
                    const value: string = event.detail.choice.value;
    
                    if (values?.includes(value)) {
                        setTimeout((): Choices => this.choices.removeActiveItemsByValue(value));
                    }
                });
    
                // Close dropdown when clicking on empty space between currently selected items in select list.
                this.element.find('.select__inner > .select__list').on('click', (): void => {
                    this.choices.hideDropdown();
                });
            }
    
            this.input[0].addEventListener('setValue', (event: CustomEvent): void => {
                const values: string | string[] = event.detail;
    
                if (typeof values !== 'undefined') {
                    this.setValue(event.detail);
                }
            });
    
            this.input[0].addEventListener('hideDropdown', (): void => {
                this.choices.hideDropdown();
    
                // Clear search input when closing dropdown
                if (this.settings.search) {
                    this.choices.clearInput();
                }
            });
    
            this.input[0].addEventListener('showDropdown', (): void => {
                // Focus search input when opening dropdown if search enabled.
                if (this.settings.search) {
                    this.element.find('.select__dropdown .select__choices-input--cloned').trigger('focus');
                }
    
                this.choices.showDropdown();
            });
        }
    }
    
  • URL: /components/raw/select/select.ts
  • Filesystem Path: src/patterns/components/forms/select/select.ts
  • Size: 5.8 KB
  • Handle: @select--multiple
  • Filesystem Path: src/patterns/components/forms/select/select.twig
  • References (2): @icon, @textfield

Search

<div class="textfield select--multiple select--search select ">
    <label class="textfield__label select__label  " for="select1">
        Select label
    </label>
    <div class="textfield__inner">
        <select name="select" id="select1" multiple data-search="true" class="textfield__input select__input" data-no-results-text="No results found" data-remove-item-text="Remove item">
            <option value="1">
                Lorem ipsum dolor sit amet, consectetur adipisicing elit. Veritatis error velit quidem alias nihil mollitia temporibus, maxime dicta repellat. Perspiciatis veniam doloribus, quia corporis commodi sed omnis adipisci facilis nisi.
            </option>
            <option value="2">
                Option 2
            </option>
            <option value="3">
                Option 3
            </option>
        </select>
        <svg class="icon  select__icon" focusable="false">
            <use href="../../inc/svg/global.4609ec92109fc41e7ad4764ef897ea8e.svg#"></use>
        </svg>

    </div>
</div>
{% set input %}
    <select
        name="{{ data.name }}"
        id="{{ data.id }}"
        {% if 'select--multiple' in modifier %} multiple{% endif %}
        {% if 'select--search' in modifier %} data-search="true"{% endif %}
        class="textfield__input select__input"
        {% if data.isDisabled %} disabled{% endif %}
        {% if 'select--search' in modifier %} data-no-results-text="{{ data.noResultsText }}"{% endif %}
        {% if 'select--multiple' in modifier %} data-remove-item-text="{{ data.removeItemText }}"{% endif %}
        {{ data.attributes }}
    >
        {% if data.placeholder or data.hasPlaceholder %}
            <option value="placeholder" disabled selected>
                {% if data.placeholder %}
                    {{ data.placeholder }}
                {% endif %}
            </option>
        {% endif %}
        {% for option in data.options %}
            <option
                value="{{ option.value }}"
                {% if option.isSelected %} selected {% endif %}
            >
                {{ option.name }}
            </option>
        {% endfor %}
    </select>
    {% include '@icon' with { class: 'select__icon', modifier: '', name: data.iconName } %}
{% endset %}

{% include '@textfield' with {
    data: data,
    input: input,
    class: 'select ' ~ class,
    modifier: modifier,
    labelClass: 'select__label' ~ ' ' ~ labelClass
} %}
{
  "language": "en-US",
  "data": {
    "label": "Select label",
    "id": "select1",
    "name": "select",
    "options": [
      {
        "name": "Lorem ipsum dolor sit amet, consectetur adipisicing elit. Veritatis error velit quidem alias nihil mollitia temporibus, maxime dicta repellat. Perspiciatis veniam doloribus, quia corporis commodi sed omnis adipisci facilis nisi.",
        "value": "1"
      },
      {
        "name": "Option 2",
        "value": "2"
      },
      {
        "name": "Option 3",
        "value": "3"
      }
    ],
    "noResultsText": "No results found",
    "removeItemText": "Remove item"
  },
  "modifier": "select--multiple select--search"
}
  • Content:
    .select {
        position: relative;
        margin: 0;
        cursor: pointer;
    
        &.is-disabled {
            cursor: default;
        }
    }
    
    .select__icon {
        position: absolute;
        top: 50%;
        right: 16px;
        transform: translateY(-50%);
        font-size: 24px;
        pointer-events: none;
    
        .select__container.is-open + & {
            transform: translateY(-50%) rotate(180deg);
        }
    }
    
    .select__inner {
        padding-right: calc(24px + 4px);
        min-height: 32px;
        height: auto;
        box-shadow: $elevation-01;
        display: flex;
        align-items: center;
    
        .select__container.is-focused & {
            border-color: $L-border-focus;
        }
    }
    
    .select__dropdown {
        visibility: hidden;
        z-index: 2;
        position: absolute;
        top: 100%;
        width: 100%;
        background-color: $L-background-weak;
        border: none;
        overflow: hidden;
        word-break: break-all; /* stylelint-disable-line plugin/no-unsupported-browser-features */
        will-change: visibility;
        border-radius: $border-radius-base;
        box-shadow: $elevation-02;
    
        .select--search & {
            padding-top: 48px;
        }
    
        .select__container.is-flipped & {
            top: auto;
            bottom: 100%;
    
            .select--search & {
                padding-top: 0;
                padding-bottom: 48px;
            }
        }
    
        .select__container.is-open & {
            visibility: visible;
        }
    }
    
    .select__choices-input {
        background: transparent;
        border: none;
        appearance: none;
        height: 48px;
        display: none;
        width: 100% !important; /* overwrite plugin inline styles */
        padding: 10px 16px;
        z-index: -1;
        pointer-events: none;
        position: absolute;
        top: 100%;
        left: 0;
    
        .select__container.is-flipped & {
            top: auto;
            bottom: 100%;
        }
    
        .select--multiple:not(.select--search) & {
            color: transparent;
            outline: none;
        }
    
        .select--search .select__container.is-open & {
            pointer-events: auto;
        }
    
        &:not(select) {
            display: block;
            z-index: 3;
        }
    
        &::-ms-expand {
            display: none;
        }
    }
    
    .select__list {
        .select__dropdown & {
            padding: 8px 0;
            max-height: 220px;
            overflow-y: auto;
            will-change: scroll-position;
    
            .select--search & {
                border-top: 1px solid $L-border;
            }
    
            .select__container.is-flipped & {
                .select--search & {
                    border-top: 0;
                    border-bottom: 1px solid $L-border;
                }
            }
        }
    }
    
    .select__list--single,
    .select__list--multiple {
        overflow: hidden;
        white-space: nowrap;
        padding: 4px 0;
        width: 100%;
        height: 100%;
    }
    
    .select__list--multiple {
        overflow: visible;
        white-space: normal;
        padding: 10px 0 4px;
        line-height: 0;
    }
    
    .select__item {
        padding: 8px 16px;
        color: $L-text-black;
        font-size: $font-size-small;
        line-height: $line-height-base;
    
        .select__list--single & {
            padding: 0;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
            color: $L-text;
        }
    
        .select__list--multiple & {
            display: inline-block;
            background-color: $L-background-medium;
            font-size: 12px;
            padding: 2px 24px 2px 8px;
            margin-bottom: 6px;
            max-width: 190px;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
            border-radius: $border-radius-base;
            position: relative;
            cursor: pointer;
        }
    
        &:not(:last-child) {
            .select__list--multiple & {
                margin-right: 8px;
            }
        }
    
        &.select__item--highlighted {
            background-color: $L-background-hover;
        }
    
        &.has-no-results {
            cursor: default;
    
            &:hover {
                .select__list:not(.select__list--single) & {
                    color: $L-text;
                    background-color: transparent;
                }
            }
        }
    
        &[data-value='placeholder'] {
            color: $L-text-medium;
            font-size: $font-size-small;
            letter-spacing: $letter-spacing-50;
    
            .select__dropdown & {
                display: none;
            }
        }
    }
    
    .select__remove {
        appearance: none;
        background: transparent;
        border: 0;
        padding: 0;
        margin: 0;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        position: absolute;
        top: 0;
        right: 0;
        width: 24px;
        height: 100%;
        opacity: .8;
        cursor: pointer;
    
        .select__list--single & {
            display: none;
        }
    }
    
    .select__search-icon {
        display: none;
        font-size: 24px;
        position: absolute;
        top: 12px;
        right: 16px;
        z-index: map-get($zindex, 'default');
    
        .select__container.is-flipped & {
            top: auto;
            bottom: 12px;
        }
    
        .select--search & {
            display: inline-block;
        }
    }
    
    .select__close-icon {
        font-size: 15px;
        pointer-events: none;
    }
    
    .select__option-span {
        font-size: $font-size-tiny;
    }
    
  • URL: /components/raw/select/select.scss
  • Filesystem Path: src/patterns/components/forms/select/select.scss
  • Size: 5 KB
  • Content:
    import Choices, { Choices as ChoicesLib } from 'choices.js';
    
    import Component from '../../component/component';
    import Icon from '../../icon/icon';
    
    import '../textfield/textfield';
    
    import './select.scss';
    
    export interface ISelectSettings {
        noResultsText: string;
        search: boolean;
        removeItemText: string;
    }
    
    export default class Select extends Component {
        static initSelector: string = '.select';
    
        public settings: ISelectSettings;
        public input: JQuery;
        public choices: Choices;
        public multiple: boolean;
    
        constructor(target: HTMLElement) {
            super(target);
    
            this.input = this.element.find('.select__input');
    
            if (this.input.length) {
                this.settings = $.extend({
                    multiselect: false,
                    noResultsText: 'No results found',
                    removeItemText: 'Remove item',
                    search: false,
                }, this.input.data());
    
                this.multiple = !!this.input.attr('multiple');
    
                this.init();
            }
        }
    
        setValue(value: string | string[]): void {
            this.choices.setChoiceByValue(value);
        }
    
        init(): void {
            this.choices = new Choices(this.input[0] as HTMLInputElement, {
                callbackOnCreateTemplates: (template: ChoicesLib.Types.strToEl): Partial<ChoicesLib.Templates> => ({
                    dropdown: (classNames: ChoicesLib.ClassNames): HTMLElement => template(`
                            <div class="${classNames.list} ${classNames.listDropdown}" aria-expanded="false">
                                ${Icon.render('search', '', 'select__search-icon')}
                            </div>
                        `) as HTMLElement,
                    item: (classNames: ChoicesLib.ClassNames, data: ChoicesLib.Choice): HTMLElement => template(`
                            <div class="${classNames.item}" data-item data-id="${data.id}" data-value="${data.value}" ${data.active ? 'aria-selected="true"' : ''} ${data.disabled ? 'aria-disabled="true"' : ''} data-deletable>
                                ${data.label}
                                <button type="button" class="${classNames.button}" aria-label="${this.settings.removeItemText}" data-button>${Icon.render('close', '', 'select__close-icon')}</button>
                            </div>
                        `) as HTMLElement,
                }),
                classNames: {
                    activeState: 'is-active',
                    button: 'select__remove',
                    containerInner: 'textfield__input select__inner',
                    containerOuter: 'select__container',
                    disabledState: 'is-disabled',
                    flippedState: 'is-flipped',
                    focusState: 'is-focused',
                    group: 'select__group',
                    groupHeading: 'select__group-heading',
                    highlightedState: 'select__item--highlighted',
                    input: 'select__choices-input',
                    inputCloned: 'select__choices-input--cloned',
                    item: 'select__item',
                    itemChoice: 'select__item--choice',
                    itemDisabled: 'select__item--disabled',
                    itemSelectable: 'select__item--selectable',
                    list: 'select__list',
                    listDropdown: 'select__dropdown',
                    listItems: 'select__list--multiple',
                    listSingle: 'select__list--single',
                    loadingState: 'is-loading',
                    noChoices: 'has-no-choices',
                    noResults: 'has-no-results',
                    openState: 'is-open',
                    placeholder: 'select__placeholder',
                    selectedState: 'is-selected',
                },
                editItems: false,
                itemSelectText: '',
                noResultsText: this.settings.noResultsText,
                removeItemButton: true,
                removeItems: true,
                renderSelectedChoices: 'always',
                searchChoices: this.settings.search,
                searchEnabled: this.settings.search,
            });
    
            this.addEventListeners();
        }
    
        addEventListeners(): void {
            // Multiselect context
            if (this.multiple) {
                // Deselect a selected item when clicking on it.
                this.input[0].addEventListener('choice', (event: CustomEvent) => {
                    const values: string[] | string = this.choices.getValue(true);
                    const value: string = event.detail.choice.value;
    
                    if (values?.includes(value)) {
                        setTimeout((): Choices => this.choices.removeActiveItemsByValue(value));
                    }
                });
    
                // Close dropdown when clicking on empty space between currently selected items in select list.
                this.element.find('.select__inner > .select__list').on('click', (): void => {
                    this.choices.hideDropdown();
                });
            }
    
            this.input[0].addEventListener('setValue', (event: CustomEvent): void => {
                const values: string | string[] = event.detail;
    
                if (typeof values !== 'undefined') {
                    this.setValue(event.detail);
                }
            });
    
            this.input[0].addEventListener('hideDropdown', (): void => {
                this.choices.hideDropdown();
    
                // Clear search input when closing dropdown
                if (this.settings.search) {
                    this.choices.clearInput();
                }
            });
    
            this.input[0].addEventListener('showDropdown', (): void => {
                // Focus search input when opening dropdown if search enabled.
                if (this.settings.search) {
                    this.element.find('.select__dropdown .select__choices-input--cloned').trigger('focus');
                }
    
                this.choices.showDropdown();
            });
        }
    }
    
  • URL: /components/raw/select/select.ts
  • Filesystem Path: src/patterns/components/forms/select/select.ts
  • Size: 5.8 KB
  • Handle: @select--search
  • Filesystem Path: src/patterns/components/forms/select/select.twig
  • References (2): @icon, @textfield

Invalid

<div class="textfield select  is-invalid">
    <label class="textfield__label select__label  " for="select1">
        Select label
    </label>
    <div class="textfield__inner">
        <select name="select" id="select1" class="textfield__input select__input">
            <option value="1">
                Lorem ipsum dolor sit amet, consectetur adipisicing elit. Veritatis error velit quidem alias nihil mollitia temporibus, maxime dicta repellat. Perspiciatis veniam doloribus, quia corporis commodi sed omnis adipisci facilis nisi.
            </option>
            <option value="2">
                Option 2
            </option>
            <option value="3">
                Option 3
            </option>
        </select>
        <svg class="icon  select__icon" focusable="false">
            <use href="../../inc/svg/global.4609ec92109fc41e7ad4764ef897ea8e.svg#"></use>
        </svg>

    </div>
    <div class="textfield__error">
        Please check your input
    </div>
</div>
{% set input %}
    <select
        name="{{ data.name }}"
        id="{{ data.id }}"
        {% if 'select--multiple' in modifier %} multiple{% endif %}
        {% if 'select--search' in modifier %} data-search="true"{% endif %}
        class="textfield__input select__input"
        {% if data.isDisabled %} disabled{% endif %}
        {% if 'select--search' in modifier %} data-no-results-text="{{ data.noResultsText }}"{% endif %}
        {% if 'select--multiple' in modifier %} data-remove-item-text="{{ data.removeItemText }}"{% endif %}
        {{ data.attributes }}
    >
        {% if data.placeholder or data.hasPlaceholder %}
            <option value="placeholder" disabled selected>
                {% if data.placeholder %}
                    {{ data.placeholder }}
                {% endif %}
            </option>
        {% endif %}
        {% for option in data.options %}
            <option
                value="{{ option.value }}"
                {% if option.isSelected %} selected {% endif %}
            >
                {{ option.name }}
            </option>
        {% endfor %}
    </select>
    {% include '@icon' with { class: 'select__icon', modifier: '', name: data.iconName } %}
{% endset %}

{% include '@textfield' with {
    data: data,
    input: input,
    class: 'select ' ~ class,
    modifier: modifier,
    labelClass: 'select__label' ~ ' ' ~ labelClass
} %}
{
  "language": "en-US",
  "data": {
    "label": "Select label",
    "id": "select1",
    "name": "select",
    "options": [
      {
        "name": "Lorem ipsum dolor sit amet, consectetur adipisicing elit. Veritatis error velit quidem alias nihil mollitia temporibus, maxime dicta repellat. Perspiciatis veniam doloribus, quia corporis commodi sed omnis adipisci facilis nisi.",
        "value": "1"
      },
      {
        "name": "Option 2",
        "value": "2"
      },
      {
        "name": "Option 3",
        "value": "3"
      }
    ],
    "isInvalid": true,
    "error": "Please check your input"
  }
}
  • Content:
    .select {
        position: relative;
        margin: 0;
        cursor: pointer;
    
        &.is-disabled {
            cursor: default;
        }
    }
    
    .select__icon {
        position: absolute;
        top: 50%;
        right: 16px;
        transform: translateY(-50%);
        font-size: 24px;
        pointer-events: none;
    
        .select__container.is-open + & {
            transform: translateY(-50%) rotate(180deg);
        }
    }
    
    .select__inner {
        padding-right: calc(24px + 4px);
        min-height: 32px;
        height: auto;
        box-shadow: $elevation-01;
        display: flex;
        align-items: center;
    
        .select__container.is-focused & {
            border-color: $L-border-focus;
        }
    }
    
    .select__dropdown {
        visibility: hidden;
        z-index: 2;
        position: absolute;
        top: 100%;
        width: 100%;
        background-color: $L-background-weak;
        border: none;
        overflow: hidden;
        word-break: break-all; /* stylelint-disable-line plugin/no-unsupported-browser-features */
        will-change: visibility;
        border-radius: $border-radius-base;
        box-shadow: $elevation-02;
    
        .select--search & {
            padding-top: 48px;
        }
    
        .select__container.is-flipped & {
            top: auto;
            bottom: 100%;
    
            .select--search & {
                padding-top: 0;
                padding-bottom: 48px;
            }
        }
    
        .select__container.is-open & {
            visibility: visible;
        }
    }
    
    .select__choices-input {
        background: transparent;
        border: none;
        appearance: none;
        height: 48px;
        display: none;
        width: 100% !important; /* overwrite plugin inline styles */
        padding: 10px 16px;
        z-index: -1;
        pointer-events: none;
        position: absolute;
        top: 100%;
        left: 0;
    
        .select__container.is-flipped & {
            top: auto;
            bottom: 100%;
        }
    
        .select--multiple:not(.select--search) & {
            color: transparent;
            outline: none;
        }
    
        .select--search .select__container.is-open & {
            pointer-events: auto;
        }
    
        &:not(select) {
            display: block;
            z-index: 3;
        }
    
        &::-ms-expand {
            display: none;
        }
    }
    
    .select__list {
        .select__dropdown & {
            padding: 8px 0;
            max-height: 220px;
            overflow-y: auto;
            will-change: scroll-position;
    
            .select--search & {
                border-top: 1px solid $L-border;
            }
    
            .select__container.is-flipped & {
                .select--search & {
                    border-top: 0;
                    border-bottom: 1px solid $L-border;
                }
            }
        }
    }
    
    .select__list--single,
    .select__list--multiple {
        overflow: hidden;
        white-space: nowrap;
        padding: 4px 0;
        width: 100%;
        height: 100%;
    }
    
    .select__list--multiple {
        overflow: visible;
        white-space: normal;
        padding: 10px 0 4px;
        line-height: 0;
    }
    
    .select__item {
        padding: 8px 16px;
        color: $L-text-black;
        font-size: $font-size-small;
        line-height: $line-height-base;
    
        .select__list--single & {
            padding: 0;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
            color: $L-text;
        }
    
        .select__list--multiple & {
            display: inline-block;
            background-color: $L-background-medium;
            font-size: 12px;
            padding: 2px 24px 2px 8px;
            margin-bottom: 6px;
            max-width: 190px;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
            border-radius: $border-radius-base;
            position: relative;
            cursor: pointer;
        }
    
        &:not(:last-child) {
            .select__list--multiple & {
                margin-right: 8px;
            }
        }
    
        &.select__item--highlighted {
            background-color: $L-background-hover;
        }
    
        &.has-no-results {
            cursor: default;
    
            &:hover {
                .select__list:not(.select__list--single) & {
                    color: $L-text;
                    background-color: transparent;
                }
            }
        }
    
        &[data-value='placeholder'] {
            color: $L-text-medium;
            font-size: $font-size-small;
            letter-spacing: $letter-spacing-50;
    
            .select__dropdown & {
                display: none;
            }
        }
    }
    
    .select__remove {
        appearance: none;
        background: transparent;
        border: 0;
        padding: 0;
        margin: 0;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        position: absolute;
        top: 0;
        right: 0;
        width: 24px;
        height: 100%;
        opacity: .8;
        cursor: pointer;
    
        .select__list--single & {
            display: none;
        }
    }
    
    .select__search-icon {
        display: none;
        font-size: 24px;
        position: absolute;
        top: 12px;
        right: 16px;
        z-index: map-get($zindex, 'default');
    
        .select__container.is-flipped & {
            top: auto;
            bottom: 12px;
        }
    
        .select--search & {
            display: inline-block;
        }
    }
    
    .select__close-icon {
        font-size: 15px;
        pointer-events: none;
    }
    
    .select__option-span {
        font-size: $font-size-tiny;
    }
    
  • URL: /components/raw/select/select.scss
  • Filesystem Path: src/patterns/components/forms/select/select.scss
  • Size: 5 KB
  • Content:
    import Choices, { Choices as ChoicesLib } from 'choices.js';
    
    import Component from '../../component/component';
    import Icon from '../../icon/icon';
    
    import '../textfield/textfield';
    
    import './select.scss';
    
    export interface ISelectSettings {
        noResultsText: string;
        search: boolean;
        removeItemText: string;
    }
    
    export default class Select extends Component {
        static initSelector: string = '.select';
    
        public settings: ISelectSettings;
        public input: JQuery;
        public choices: Choices;
        public multiple: boolean;
    
        constructor(target: HTMLElement) {
            super(target);
    
            this.input = this.element.find('.select__input');
    
            if (this.input.length) {
                this.settings = $.extend({
                    multiselect: false,
                    noResultsText: 'No results found',
                    removeItemText: 'Remove item',
                    search: false,
                }, this.input.data());
    
                this.multiple = !!this.input.attr('multiple');
    
                this.init();
            }
        }
    
        setValue(value: string | string[]): void {
            this.choices.setChoiceByValue(value);
        }
    
        init(): void {
            this.choices = new Choices(this.input[0] as HTMLInputElement, {
                callbackOnCreateTemplates: (template: ChoicesLib.Types.strToEl): Partial<ChoicesLib.Templates> => ({
                    dropdown: (classNames: ChoicesLib.ClassNames): HTMLElement => template(`
                            <div class="${classNames.list} ${classNames.listDropdown}" aria-expanded="false">
                                ${Icon.render('search', '', 'select__search-icon')}
                            </div>
                        `) as HTMLElement,
                    item: (classNames: ChoicesLib.ClassNames, data: ChoicesLib.Choice): HTMLElement => template(`
                            <div class="${classNames.item}" data-item data-id="${data.id}" data-value="${data.value}" ${data.active ? 'aria-selected="true"' : ''} ${data.disabled ? 'aria-disabled="true"' : ''} data-deletable>
                                ${data.label}
                                <button type="button" class="${classNames.button}" aria-label="${this.settings.removeItemText}" data-button>${Icon.render('close', '', 'select__close-icon')}</button>
                            </div>
                        `) as HTMLElement,
                }),
                classNames: {
                    activeState: 'is-active',
                    button: 'select__remove',
                    containerInner: 'textfield__input select__inner',
                    containerOuter: 'select__container',
                    disabledState: 'is-disabled',
                    flippedState: 'is-flipped',
                    focusState: 'is-focused',
                    group: 'select__group',
                    groupHeading: 'select__group-heading',
                    highlightedState: 'select__item--highlighted',
                    input: 'select__choices-input',
                    inputCloned: 'select__choices-input--cloned',
                    item: 'select__item',
                    itemChoice: 'select__item--choice',
                    itemDisabled: 'select__item--disabled',
                    itemSelectable: 'select__item--selectable',
                    list: 'select__list',
                    listDropdown: 'select__dropdown',
                    listItems: 'select__list--multiple',
                    listSingle: 'select__list--single',
                    loadingState: 'is-loading',
                    noChoices: 'has-no-choices',
                    noResults: 'has-no-results',
                    openState: 'is-open',
                    placeholder: 'select__placeholder',
                    selectedState: 'is-selected',
                },
                editItems: false,
                itemSelectText: '',
                noResultsText: this.settings.noResultsText,
                removeItemButton: true,
                removeItems: true,
                renderSelectedChoices: 'always',
                searchChoices: this.settings.search,
                searchEnabled: this.settings.search,
            });
    
            this.addEventListeners();
        }
    
        addEventListeners(): void {
            // Multiselect context
            if (this.multiple) {
                // Deselect a selected item when clicking on it.
                this.input[0].addEventListener('choice', (event: CustomEvent) => {
                    const values: string[] | string = this.choices.getValue(true);
                    const value: string = event.detail.choice.value;
    
                    if (values?.includes(value)) {
                        setTimeout((): Choices => this.choices.removeActiveItemsByValue(value));
                    }
                });
    
                // Close dropdown when clicking on empty space between currently selected items in select list.
                this.element.find('.select__inner > .select__list').on('click', (): void => {
                    this.choices.hideDropdown();
                });
            }
    
            this.input[0].addEventListener('setValue', (event: CustomEvent): void => {
                const values: string | string[] = event.detail;
    
                if (typeof values !== 'undefined') {
                    this.setValue(event.detail);
                }
            });
    
            this.input[0].addEventListener('hideDropdown', (): void => {
                this.choices.hideDropdown();
    
                // Clear search input when closing dropdown
                if (this.settings.search) {
                    this.choices.clearInput();
                }
            });
    
            this.input[0].addEventListener('showDropdown', (): void => {
                // Focus search input when opening dropdown if search enabled.
                if (this.settings.search) {
                    this.element.find('.select__dropdown .select__choices-input--cloned').trigger('focus');
                }
    
                this.choices.showDropdown();
            });
        }
    }
    
  • URL: /components/raw/select/select.ts
  • Filesystem Path: src/patterns/components/forms/select/select.ts
  • Size: 5.8 KB
  • Handle: @select--invalid
  • Filesystem Path: src/patterns/components/forms/select/select.twig
  • References (2): @icon, @textfield

Disabled

<div class="textfield select  is-disabled">
    <label class="textfield__label select__label  " for="select1">
        Select label
    </label>
    <div class="textfield__inner">
        <select name="select" id="select1" class="textfield__input select__input" disabled>
            <option value="1">
                Lorem ipsum dolor sit amet, consectetur adipisicing elit. Veritatis error velit quidem alias nihil mollitia temporibus, maxime dicta repellat. Perspiciatis veniam doloribus, quia corporis commodi sed omnis adipisci facilis nisi.
            </option>
            <option value="2">
                Option 2
            </option>
            <option value="3">
                Option 3
            </option>
        </select>
        <svg class="icon  select__icon" focusable="false">
            <use href="../../inc/svg/global.4609ec92109fc41e7ad4764ef897ea8e.svg#"></use>
        </svg>

    </div>
</div>
{% set input %}
    <select
        name="{{ data.name }}"
        id="{{ data.id }}"
        {% if 'select--multiple' in modifier %} multiple{% endif %}
        {% if 'select--search' in modifier %} data-search="true"{% endif %}
        class="textfield__input select__input"
        {% if data.isDisabled %} disabled{% endif %}
        {% if 'select--search' in modifier %} data-no-results-text="{{ data.noResultsText }}"{% endif %}
        {% if 'select--multiple' in modifier %} data-remove-item-text="{{ data.removeItemText }}"{% endif %}
        {{ data.attributes }}
    >
        {% if data.placeholder or data.hasPlaceholder %}
            <option value="placeholder" disabled selected>
                {% if data.placeholder %}
                    {{ data.placeholder }}
                {% endif %}
            </option>
        {% endif %}
        {% for option in data.options %}
            <option
                value="{{ option.value }}"
                {% if option.isSelected %} selected {% endif %}
            >
                {{ option.name }}
            </option>
        {% endfor %}
    </select>
    {% include '@icon' with { class: 'select__icon', modifier: '', name: data.iconName } %}
{% endset %}

{% include '@textfield' with {
    data: data,
    input: input,
    class: 'select ' ~ class,
    modifier: modifier,
    labelClass: 'select__label' ~ ' ' ~ labelClass
} %}
{
  "language": "en-US",
  "data": {
    "label": "Select label",
    "id": "select1",
    "name": "select",
    "options": [
      {
        "name": "Lorem ipsum dolor sit amet, consectetur adipisicing elit. Veritatis error velit quidem alias nihil mollitia temporibus, maxime dicta repellat. Perspiciatis veniam doloribus, quia corporis commodi sed omnis adipisci facilis nisi.",
        "value": "1"
      },
      {
        "name": "Option 2",
        "value": "2"
      },
      {
        "name": "Option 3",
        "value": "3"
      }
    ],
    "isDisabled": true,
    "value": "Tere"
  }
}
  • Content:
    .select {
        position: relative;
        margin: 0;
        cursor: pointer;
    
        &.is-disabled {
            cursor: default;
        }
    }
    
    .select__icon {
        position: absolute;
        top: 50%;
        right: 16px;
        transform: translateY(-50%);
        font-size: 24px;
        pointer-events: none;
    
        .select__container.is-open + & {
            transform: translateY(-50%) rotate(180deg);
        }
    }
    
    .select__inner {
        padding-right: calc(24px + 4px);
        min-height: 32px;
        height: auto;
        box-shadow: $elevation-01;
        display: flex;
        align-items: center;
    
        .select__container.is-focused & {
            border-color: $L-border-focus;
        }
    }
    
    .select__dropdown {
        visibility: hidden;
        z-index: 2;
        position: absolute;
        top: 100%;
        width: 100%;
        background-color: $L-background-weak;
        border: none;
        overflow: hidden;
        word-break: break-all; /* stylelint-disable-line plugin/no-unsupported-browser-features */
        will-change: visibility;
        border-radius: $border-radius-base;
        box-shadow: $elevation-02;
    
        .select--search & {
            padding-top: 48px;
        }
    
        .select__container.is-flipped & {
            top: auto;
            bottom: 100%;
    
            .select--search & {
                padding-top: 0;
                padding-bottom: 48px;
            }
        }
    
        .select__container.is-open & {
            visibility: visible;
        }
    }
    
    .select__choices-input {
        background: transparent;
        border: none;
        appearance: none;
        height: 48px;
        display: none;
        width: 100% !important; /* overwrite plugin inline styles */
        padding: 10px 16px;
        z-index: -1;
        pointer-events: none;
        position: absolute;
        top: 100%;
        left: 0;
    
        .select__container.is-flipped & {
            top: auto;
            bottom: 100%;
        }
    
        .select--multiple:not(.select--search) & {
            color: transparent;
            outline: none;
        }
    
        .select--search .select__container.is-open & {
            pointer-events: auto;
        }
    
        &:not(select) {
            display: block;
            z-index: 3;
        }
    
        &::-ms-expand {
            display: none;
        }
    }
    
    .select__list {
        .select__dropdown & {
            padding: 8px 0;
            max-height: 220px;
            overflow-y: auto;
            will-change: scroll-position;
    
            .select--search & {
                border-top: 1px solid $L-border;
            }
    
            .select__container.is-flipped & {
                .select--search & {
                    border-top: 0;
                    border-bottom: 1px solid $L-border;
                }
            }
        }
    }
    
    .select__list--single,
    .select__list--multiple {
        overflow: hidden;
        white-space: nowrap;
        padding: 4px 0;
        width: 100%;
        height: 100%;
    }
    
    .select__list--multiple {
        overflow: visible;
        white-space: normal;
        padding: 10px 0 4px;
        line-height: 0;
    }
    
    .select__item {
        padding: 8px 16px;
        color: $L-text-black;
        font-size: $font-size-small;
        line-height: $line-height-base;
    
        .select__list--single & {
            padding: 0;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
            color: $L-text;
        }
    
        .select__list--multiple & {
            display: inline-block;
            background-color: $L-background-medium;
            font-size: 12px;
            padding: 2px 24px 2px 8px;
            margin-bottom: 6px;
            max-width: 190px;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
            border-radius: $border-radius-base;
            position: relative;
            cursor: pointer;
        }
    
        &:not(:last-child) {
            .select__list--multiple & {
                margin-right: 8px;
            }
        }
    
        &.select__item--highlighted {
            background-color: $L-background-hover;
        }
    
        &.has-no-results {
            cursor: default;
    
            &:hover {
                .select__list:not(.select__list--single) & {
                    color: $L-text;
                    background-color: transparent;
                }
            }
        }
    
        &[data-value='placeholder'] {
            color: $L-text-medium;
            font-size: $font-size-small;
            letter-spacing: $letter-spacing-50;
    
            .select__dropdown & {
                display: none;
            }
        }
    }
    
    .select__remove {
        appearance: none;
        background: transparent;
        border: 0;
        padding: 0;
        margin: 0;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        position: absolute;
        top: 0;
        right: 0;
        width: 24px;
        height: 100%;
        opacity: .8;
        cursor: pointer;
    
        .select__list--single & {
            display: none;
        }
    }
    
    .select__search-icon {
        display: none;
        font-size: 24px;
        position: absolute;
        top: 12px;
        right: 16px;
        z-index: map-get($zindex, 'default');
    
        .select__container.is-flipped & {
            top: auto;
            bottom: 12px;
        }
    
        .select--search & {
            display: inline-block;
        }
    }
    
    .select__close-icon {
        font-size: 15px;
        pointer-events: none;
    }
    
    .select__option-span {
        font-size: $font-size-tiny;
    }
    
  • URL: /components/raw/select/select.scss
  • Filesystem Path: src/patterns/components/forms/select/select.scss
  • Size: 5 KB
  • Content:
    import Choices, { Choices as ChoicesLib } from 'choices.js';
    
    import Component from '../../component/component';
    import Icon from '../../icon/icon';
    
    import '../textfield/textfield';
    
    import './select.scss';
    
    export interface ISelectSettings {
        noResultsText: string;
        search: boolean;
        removeItemText: string;
    }
    
    export default class Select extends Component {
        static initSelector: string = '.select';
    
        public settings: ISelectSettings;
        public input: JQuery;
        public choices: Choices;
        public multiple: boolean;
    
        constructor(target: HTMLElement) {
            super(target);
    
            this.input = this.element.find('.select__input');
    
            if (this.input.length) {
                this.settings = $.extend({
                    multiselect: false,
                    noResultsText: 'No results found',
                    removeItemText: 'Remove item',
                    search: false,
                }, this.input.data());
    
                this.multiple = !!this.input.attr('multiple');
    
                this.init();
            }
        }
    
        setValue(value: string | string[]): void {
            this.choices.setChoiceByValue(value);
        }
    
        init(): void {
            this.choices = new Choices(this.input[0] as HTMLInputElement, {
                callbackOnCreateTemplates: (template: ChoicesLib.Types.strToEl): Partial<ChoicesLib.Templates> => ({
                    dropdown: (classNames: ChoicesLib.ClassNames): HTMLElement => template(`
                            <div class="${classNames.list} ${classNames.listDropdown}" aria-expanded="false">
                                ${Icon.render('search', '', 'select__search-icon')}
                            </div>
                        `) as HTMLElement,
                    item: (classNames: ChoicesLib.ClassNames, data: ChoicesLib.Choice): HTMLElement => template(`
                            <div class="${classNames.item}" data-item data-id="${data.id}" data-value="${data.value}" ${data.active ? 'aria-selected="true"' : ''} ${data.disabled ? 'aria-disabled="true"' : ''} data-deletable>
                                ${data.label}
                                <button type="button" class="${classNames.button}" aria-label="${this.settings.removeItemText}" data-button>${Icon.render('close', '', 'select__close-icon')}</button>
                            </div>
                        `) as HTMLElement,
                }),
                classNames: {
                    activeState: 'is-active',
                    button: 'select__remove',
                    containerInner: 'textfield__input select__inner',
                    containerOuter: 'select__container',
                    disabledState: 'is-disabled',
                    flippedState: 'is-flipped',
                    focusState: 'is-focused',
                    group: 'select__group',
                    groupHeading: 'select__group-heading',
                    highlightedState: 'select__item--highlighted',
                    input: 'select__choices-input',
                    inputCloned: 'select__choices-input--cloned',
                    item: 'select__item',
                    itemChoice: 'select__item--choice',
                    itemDisabled: 'select__item--disabled',
                    itemSelectable: 'select__item--selectable',
                    list: 'select__list',
                    listDropdown: 'select__dropdown',
                    listItems: 'select__list--multiple',
                    listSingle: 'select__list--single',
                    loadingState: 'is-loading',
                    noChoices: 'has-no-choices',
                    noResults: 'has-no-results',
                    openState: 'is-open',
                    placeholder: 'select__placeholder',
                    selectedState: 'is-selected',
                },
                editItems: false,
                itemSelectText: '',
                noResultsText: this.settings.noResultsText,
                removeItemButton: true,
                removeItems: true,
                renderSelectedChoices: 'always',
                searchChoices: this.settings.search,
                searchEnabled: this.settings.search,
            });
    
            this.addEventListeners();
        }
    
        addEventListeners(): void {
            // Multiselect context
            if (this.multiple) {
                // Deselect a selected item when clicking on it.
                this.input[0].addEventListener('choice', (event: CustomEvent) => {
                    const values: string[] | string = this.choices.getValue(true);
                    const value: string = event.detail.choice.value;
    
                    if (values?.includes(value)) {
                        setTimeout((): Choices => this.choices.removeActiveItemsByValue(value));
                    }
                });
    
                // Close dropdown when clicking on empty space between currently selected items in select list.
                this.element.find('.select__inner > .select__list').on('click', (): void => {
                    this.choices.hideDropdown();
                });
            }
    
            this.input[0].addEventListener('setValue', (event: CustomEvent): void => {
                const values: string | string[] = event.detail;
    
                if (typeof values !== 'undefined') {
                    this.setValue(event.detail);
                }
            });
    
            this.input[0].addEventListener('hideDropdown', (): void => {
                this.choices.hideDropdown();
    
                // Clear search input when closing dropdown
                if (this.settings.search) {
                    this.choices.clearInput();
                }
            });
    
            this.input[0].addEventListener('showDropdown', (): void => {
                // Focus search input when opening dropdown if search enabled.
                if (this.settings.search) {
                    this.element.find('.select__dropdown .select__choices-input--cloned').trigger('focus');
                }
    
                this.choices.showDropdown();
            });
        }
    }
    
  • URL: /components/raw/select/select.ts
  • Filesystem Path: src/patterns/components/forms/select/select.ts
  • Size: 5.8 KB
  • Handle: @select--disabled
  • Filesystem Path: src/patterns/components/forms/select/select.twig
  • References (2): @icon, @textfield

Hidden Label

<div class="textfield select ">
    <label class="textfield__label select__label  h-visually-hidden" for="select1">
        Select label
    </label>
    <div class="textfield__inner">
        <select name="select" id="select1" class="textfield__input select__input">
            <option value="1">
                Lorem ipsum dolor sit amet, consectetur adipisicing elit. Veritatis error velit quidem alias nihil mollitia temporibus, maxime dicta repellat. Perspiciatis veniam doloribus, quia corporis commodi sed omnis adipisci facilis nisi.
            </option>
            <option value="2">
                Option 2
            </option>
            <option value="3">
                Option 3
            </option>
        </select>
        <svg class="icon  select__icon" focusable="false">
            <use href="../../inc/svg/global.4609ec92109fc41e7ad4764ef897ea8e.svg#"></use>
        </svg>

    </div>
</div>
{% set input %}
    <select
        name="{{ data.name }}"
        id="{{ data.id }}"
        {% if 'select--multiple' in modifier %} multiple{% endif %}
        {% if 'select--search' in modifier %} data-search="true"{% endif %}
        class="textfield__input select__input"
        {% if data.isDisabled %} disabled{% endif %}
        {% if 'select--search' in modifier %} data-no-results-text="{{ data.noResultsText }}"{% endif %}
        {% if 'select--multiple' in modifier %} data-remove-item-text="{{ data.removeItemText }}"{% endif %}
        {{ data.attributes }}
    >
        {% if data.placeholder or data.hasPlaceholder %}
            <option value="placeholder" disabled selected>
                {% if data.placeholder %}
                    {{ data.placeholder }}
                {% endif %}
            </option>
        {% endif %}
        {% for option in data.options %}
            <option
                value="{{ option.value }}"
                {% if option.isSelected %} selected {% endif %}
            >
                {{ option.name }}
            </option>
        {% endfor %}
    </select>
    {% include '@icon' with { class: 'select__icon', modifier: '', name: data.iconName } %}
{% endset %}

{% include '@textfield' with {
    data: data,
    input: input,
    class: 'select ' ~ class,
    modifier: modifier,
    labelClass: 'select__label' ~ ' ' ~ labelClass
} %}
{
  "language": "en-US",
  "data": {
    "label": "Select label",
    "id": "select1",
    "name": "select",
    "options": [
      {
        "name": "Lorem ipsum dolor sit amet, consectetur adipisicing elit. Veritatis error velit quidem alias nihil mollitia temporibus, maxime dicta repellat. Perspiciatis veniam doloribus, quia corporis commodi sed omnis adipisci facilis nisi.",
        "value": "1"
      },
      {
        "name": "Option 2",
        "value": "2"
      },
      {
        "name": "Option 3",
        "value": "3"
      }
    ],
    "isLabelHidden": true
  }
}
  • Content:
    .select {
        position: relative;
        margin: 0;
        cursor: pointer;
    
        &.is-disabled {
            cursor: default;
        }
    }
    
    .select__icon {
        position: absolute;
        top: 50%;
        right: 16px;
        transform: translateY(-50%);
        font-size: 24px;
        pointer-events: none;
    
        .select__container.is-open + & {
            transform: translateY(-50%) rotate(180deg);
        }
    }
    
    .select__inner {
        padding-right: calc(24px + 4px);
        min-height: 32px;
        height: auto;
        box-shadow: $elevation-01;
        display: flex;
        align-items: center;
    
        .select__container.is-focused & {
            border-color: $L-border-focus;
        }
    }
    
    .select__dropdown {
        visibility: hidden;
        z-index: 2;
        position: absolute;
        top: 100%;
        width: 100%;
        background-color: $L-background-weak;
        border: none;
        overflow: hidden;
        word-break: break-all; /* stylelint-disable-line plugin/no-unsupported-browser-features */
        will-change: visibility;
        border-radius: $border-radius-base;
        box-shadow: $elevation-02;
    
        .select--search & {
            padding-top: 48px;
        }
    
        .select__container.is-flipped & {
            top: auto;
            bottom: 100%;
    
            .select--search & {
                padding-top: 0;
                padding-bottom: 48px;
            }
        }
    
        .select__container.is-open & {
            visibility: visible;
        }
    }
    
    .select__choices-input {
        background: transparent;
        border: none;
        appearance: none;
        height: 48px;
        display: none;
        width: 100% !important; /* overwrite plugin inline styles */
        padding: 10px 16px;
        z-index: -1;
        pointer-events: none;
        position: absolute;
        top: 100%;
        left: 0;
    
        .select__container.is-flipped & {
            top: auto;
            bottom: 100%;
        }
    
        .select--multiple:not(.select--search) & {
            color: transparent;
            outline: none;
        }
    
        .select--search .select__container.is-open & {
            pointer-events: auto;
        }
    
        &:not(select) {
            display: block;
            z-index: 3;
        }
    
        &::-ms-expand {
            display: none;
        }
    }
    
    .select__list {
        .select__dropdown & {
            padding: 8px 0;
            max-height: 220px;
            overflow-y: auto;
            will-change: scroll-position;
    
            .select--search & {
                border-top: 1px solid $L-border;
            }
    
            .select__container.is-flipped & {
                .select--search & {
                    border-top: 0;
                    border-bottom: 1px solid $L-border;
                }
            }
        }
    }
    
    .select__list--single,
    .select__list--multiple {
        overflow: hidden;
        white-space: nowrap;
        padding: 4px 0;
        width: 100%;
        height: 100%;
    }
    
    .select__list--multiple {
        overflow: visible;
        white-space: normal;
        padding: 10px 0 4px;
        line-height: 0;
    }
    
    .select__item {
        padding: 8px 16px;
        color: $L-text-black;
        font-size: $font-size-small;
        line-height: $line-height-base;
    
        .select__list--single & {
            padding: 0;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
            color: $L-text;
        }
    
        .select__list--multiple & {
            display: inline-block;
            background-color: $L-background-medium;
            font-size: 12px;
            padding: 2px 24px 2px 8px;
            margin-bottom: 6px;
            max-width: 190px;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
            border-radius: $border-radius-base;
            position: relative;
            cursor: pointer;
        }
    
        &:not(:last-child) {
            .select__list--multiple & {
                margin-right: 8px;
            }
        }
    
        &.select__item--highlighted {
            background-color: $L-background-hover;
        }
    
        &.has-no-results {
            cursor: default;
    
            &:hover {
                .select__list:not(.select__list--single) & {
                    color: $L-text;
                    background-color: transparent;
                }
            }
        }
    
        &[data-value='placeholder'] {
            color: $L-text-medium;
            font-size: $font-size-small;
            letter-spacing: $letter-spacing-50;
    
            .select__dropdown & {
                display: none;
            }
        }
    }
    
    .select__remove {
        appearance: none;
        background: transparent;
        border: 0;
        padding: 0;
        margin: 0;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        position: absolute;
        top: 0;
        right: 0;
        width: 24px;
        height: 100%;
        opacity: .8;
        cursor: pointer;
    
        .select__list--single & {
            display: none;
        }
    }
    
    .select__search-icon {
        display: none;
        font-size: 24px;
        position: absolute;
        top: 12px;
        right: 16px;
        z-index: map-get($zindex, 'default');
    
        .select__container.is-flipped & {
            top: auto;
            bottom: 12px;
        }
    
        .select--search & {
            display: inline-block;
        }
    }
    
    .select__close-icon {
        font-size: 15px;
        pointer-events: none;
    }
    
    .select__option-span {
        font-size: $font-size-tiny;
    }
    
  • URL: /components/raw/select/select.scss
  • Filesystem Path: src/patterns/components/forms/select/select.scss
  • Size: 5 KB
  • Content:
    import Choices, { Choices as ChoicesLib } from 'choices.js';
    
    import Component from '../../component/component';
    import Icon from '../../icon/icon';
    
    import '../textfield/textfield';
    
    import './select.scss';
    
    export interface ISelectSettings {
        noResultsText: string;
        search: boolean;
        removeItemText: string;
    }
    
    export default class Select extends Component {
        static initSelector: string = '.select';
    
        public settings: ISelectSettings;
        public input: JQuery;
        public choices: Choices;
        public multiple: boolean;
    
        constructor(target: HTMLElement) {
            super(target);
    
            this.input = this.element.find('.select__input');
    
            if (this.input.length) {
                this.settings = $.extend({
                    multiselect: false,
                    noResultsText: 'No results found',
                    removeItemText: 'Remove item',
                    search: false,
                }, this.input.data());
    
                this.multiple = !!this.input.attr('multiple');
    
                this.init();
            }
        }
    
        setValue(value: string | string[]): void {
            this.choices.setChoiceByValue(value);
        }
    
        init(): void {
            this.choices = new Choices(this.input[0] as HTMLInputElement, {
                callbackOnCreateTemplates: (template: ChoicesLib.Types.strToEl): Partial<ChoicesLib.Templates> => ({
                    dropdown: (classNames: ChoicesLib.ClassNames): HTMLElement => template(`
                            <div class="${classNames.list} ${classNames.listDropdown}" aria-expanded="false">
                                ${Icon.render('search', '', 'select__search-icon')}
                            </div>
                        `) as HTMLElement,
                    item: (classNames: ChoicesLib.ClassNames, data: ChoicesLib.Choice): HTMLElement => template(`
                            <div class="${classNames.item}" data-item data-id="${data.id}" data-value="${data.value}" ${data.active ? 'aria-selected="true"' : ''} ${data.disabled ? 'aria-disabled="true"' : ''} data-deletable>
                                ${data.label}
                                <button type="button" class="${classNames.button}" aria-label="${this.settings.removeItemText}" data-button>${Icon.render('close', '', 'select__close-icon')}</button>
                            </div>
                        `) as HTMLElement,
                }),
                classNames: {
                    activeState: 'is-active',
                    button: 'select__remove',
                    containerInner: 'textfield__input select__inner',
                    containerOuter: 'select__container',
                    disabledState: 'is-disabled',
                    flippedState: 'is-flipped',
                    focusState: 'is-focused',
                    group: 'select__group',
                    groupHeading: 'select__group-heading',
                    highlightedState: 'select__item--highlighted',
                    input: 'select__choices-input',
                    inputCloned: 'select__choices-input--cloned',
                    item: 'select__item',
                    itemChoice: 'select__item--choice',
                    itemDisabled: 'select__item--disabled',
                    itemSelectable: 'select__item--selectable',
                    list: 'select__list',
                    listDropdown: 'select__dropdown',
                    listItems: 'select__list--multiple',
                    listSingle: 'select__list--single',
                    loadingState: 'is-loading',
                    noChoices: 'has-no-choices',
                    noResults: 'has-no-results',
                    openState: 'is-open',
                    placeholder: 'select__placeholder',
                    selectedState: 'is-selected',
                },
                editItems: false,
                itemSelectText: '',
                noResultsText: this.settings.noResultsText,
                removeItemButton: true,
                removeItems: true,
                renderSelectedChoices: 'always',
                searchChoices: this.settings.search,
                searchEnabled: this.settings.search,
            });
    
            this.addEventListeners();
        }
    
        addEventListeners(): void {
            // Multiselect context
            if (this.multiple) {
                // Deselect a selected item when clicking on it.
                this.input[0].addEventListener('choice', (event: CustomEvent) => {
                    const values: string[] | string = this.choices.getValue(true);
                    const value: string = event.detail.choice.value;
    
                    if (values?.includes(value)) {
                        setTimeout((): Choices => this.choices.removeActiveItemsByValue(value));
                    }
                });
    
                // Close dropdown when clicking on empty space between currently selected items in select list.
                this.element.find('.select__inner > .select__list').on('click', (): void => {
                    this.choices.hideDropdown();
                });
            }
    
            this.input[0].addEventListener('setValue', (event: CustomEvent): void => {
                const values: string | string[] = event.detail;
    
                if (typeof values !== 'undefined') {
                    this.setValue(event.detail);
                }
            });
    
            this.input[0].addEventListener('hideDropdown', (): void => {
                this.choices.hideDropdown();
    
                // Clear search input when closing dropdown
                if (this.settings.search) {
                    this.choices.clearInput();
                }
            });
    
            this.input[0].addEventListener('showDropdown', (): void => {
                // Focus search input when opening dropdown if search enabled.
                if (this.settings.search) {
                    this.element.find('.select__dropdown .select__choices-input--cloned').trigger('focus');
                }
    
                this.choices.showDropdown();
            });
        }
    }
    
  • URL: /components/raw/select/select.ts
  • Filesystem Path: src/patterns/components/forms/select/select.ts
  • Size: 5.8 KB
  • Handle: @select--hidden-label
  • Filesystem Path: src/patterns/components/forms/select/select.twig
  • References (2): @icon, @textfield