VGSelect

Стилизованный HTML Select

Мультивыбор и состояния

Теги, значения формы, disabled и динамические опции.

VGSelect сохраняет исходный <select> для формы и строит интерфейс рядом с ним. Каждый пример запускается один раз после появления HTML. Параметры из data-* читаются при инициализации; библиотека сама не сканирует страницу в поисках полей. По умолчанию модуль использует position: 'auto': список выбирает сторону с большим свободным местом.

Теги и значения формы

Выберите несколько услуг, снимите выбор повторным кликом или крестиком тега. Кнопка читает FormData без отправки формы.

Выбрано: oil, diagnostics
HTML
<form id="select-multiple-form" class="select-demo">
  <label for="select-multiple">Услуги</label>
  <select id="select-multiple" class="vg-select" name="services[]" multiple data-select-demo
    data-placeholder="Выберите услуги" data-search-enabled="true">
    <option value="oil" selected>Замена масла</option>
    <option value="diagnostics" selected>Диагностика</option>
    <option value="tires">Шиномонтаж</option>
    <option value="wash">Мойка</option>
  </select>
  <div class="select-demo-actions">
    <button id="select-multiple-read" class="btn btn-primary btn-sm" type="button">Прочитать FormData</button>
    <button id="select-multiple-clear" class="btn btn-surface btn-sm" type="button">Очистить выбор</button>
  </div>
  <output id="select-multiple-value" aria-live="polite">Выбрано: oil, diagnostics</output>
</form>
JavaScript
/**
 * Описание: рабочий пример VGSelect — multiple.
 * Возможности: инициализация и демонстрация публичного контракта на исходном select.
 */
import {VGSelect} from 'vgapp';

function initSelectDemo() {
    const select = document.querySelector('#select-multiple');
    if (!select || select.dataset.inited === 'true') return;
    VGSelect.init(select);
    const read = () => {
        const values = new FormData(document.querySelector('#select-multiple-form')).getAll('services[]');
        document.querySelector('#select-multiple-value').textContent = 'Выбрано: ' + (values.join(', ') || 'ничего');
    };
    select.addEventListener('change', read);
    document.querySelector('#select-multiple-read').addEventListener('click', read);
    document.querySelector('#select-multiple-clear').addEventListener('click', () => {
        Array.from(select.selectedOptions).forEach(option => {
            VGSelect.changeSelector(select, option.value, {selected: false});
        });
    });
}

initSelectDemo();
CSS
.select-demo {
    display: grid;
    gap: 12px;
    max-width: 560px;
    min-width: 0;
}
.select-demo-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}
.select-demo output {
    overflow-wrap: anywhere;
}
.select-demo-log {
    max-height: 240px;
    overflow: auto;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    padding: 12px;
    border: 1px solid var(--vg-border-default);
    border-radius: var(--vg-radius-md);
    background: var(--vg-surface-muted-bg);
    color: var(--vg-text-primary);
}
.select-demo-placement {
    padding-top: 180px;
}
.vg-select.select-demo-compact {
    --vg-select-current-font-size: 14px;
    --vg-select-current-padding-top: 8px;
    --vg-select-current-padding-bottom: 8px;
    --vg-select-current-border-radius: 10px;
    --vg-select-list-hover-background-color: var(--vg-surface-muted-bg);
}
.module-select-content {
    min-width: 0;
}
.module-select-reference {
    margin-top: 32px;
    overflow-wrap: anywhere;
}
.module-select-reference dt {
    margin-top: 16px;
    font-weight: 600;
}
.module-select-reference dd {
    margin: 6px 0 0;
}

Disabled и MutationObserver

Измените disabled и добавьте option обычными DOM-операциями. Компонент обновится автоматически примерно через 100 мс без повторного init.

Поле отключено; опций: 2
HTML
<div class="select-demo">
  <label for="select-states">Пост обслуживания</label>
  <select id="select-states" class="vg-select" disabled data-select-demo>
    <option value="1" selected>Пост 1</option>
    <option value="2">Пост 2</option>
  </select>
  <div class="select-demo-actions">
    <button id="select-states-toggle" class="btn btn-primary btn-sm" type="button">Разблокировать</button>
    <button id="select-states-add" class="btn btn-surface btn-sm" type="button">Добавить пост</button>
  </div>
  <output id="select-states-value" aria-live="polite">Поле отключено; опций: 2</output>
</div>
JavaScript
/**
 * Описание: рабочий пример VGSelect — states.
 * Возможности: инициализация и демонстрация публичного контракта на исходном select.
 */
import {VGSelect} from 'vgapp';

function initSelectDemo() {
    const select = document.querySelector('#select-states');
    if (!select || select.dataset.inited === 'true') return;
    VGSelect.init(select);
    const toggle = document.querySelector('#select-states-toggle');
    const report = () => {
        document.querySelector('#select-states-value').textContent =
            (select.disabled ? 'Поле отключено' : 'Поле доступно') + '; опций: ' + select.options.length;
    };
    toggle.addEventListener('click', () => {
        select.disabled = !select.disabled;
        toggle.textContent = select.disabled ? 'Разблокировать' : 'Отключить';
        report();
    });
    document.querySelector('#select-states-add').addEventListener('click', () => {
        const number = select.options.length + 1;
        select.add(new Option('Пост ' + number, String(number)));
        report(); // UI списка обновит MutationObserver.
    });
}

initSelectDemo();
CSS
.select-demo {
    display: grid;
    gap: 12px;
    max-width: 560px;
    min-width: 0;
}
.select-demo-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}
.select-demo output {
    overflow-wrap: anywhere;
}
.select-demo-log {
    max-height: 240px;
    overflow: auto;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    padding: 12px;
    border: 1px solid var(--vg-border-default);
    border-radius: var(--vg-radius-md);
    background: var(--vg-surface-muted-bg);
    color: var(--vg-text-primary);
}
.select-demo-placement {
    padding-top: 180px;
}
.vg-select.select-demo-compact {
    --vg-select-current-font-size: 14px;
    --vg-select-current-padding-top: 8px;
    --vg-select-current-padding-bottom: 8px;
    --vg-select-current-border-radius: 10px;
    --vg-select-list-hover-background-color: var(--vg-surface-muted-bg);
}
.module-select-content {
    min-width: 0;
}
.module-select-reference {
    margin-top: 32px;
    overflow-wrap: anywhere;
}
.module-select-reference dt {
    margin-top: 16px;
    font-weight: 600;
}
.module-select-reference dd {
    margin: 6px 0 0;
}