VGSelect

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

Выбор и поиск

Начальное значение, Data API, локальный поиск, группы и дерево.

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

Одиночный выбор и placeholder

Пустая hidden-опция сохраняет состояние «не выбрано». Выбранное значение читается из исходного поля.

Значение: не выбрано
Значение: не выбрано
HTML
<div class="row gap-y-6">
	<div class="col-xl-6">
		<div class="select-demo">
			<label for="select-single">Город</label>
			<select id="select-single" class="vg-select" name="city" data-select-demo
			        data-placeholder="Выберите город" data-autosearch="false">
				<option value="" selected hidden></option>
				<option value="kaluga">Калуга</option>
				<option value="moscow">Москва</option>
				<option value="tula">Тула</option>
			</select>
			<output id="select-single-value" aria-live="polite">Значение: не выбрано</output>
		</div>
	</div>

	<div class="col-xl-6">
		<div class="select-demo">
			<label for="select-single">Много городов</label>
			<select id="select-single-more" class="vg-select" name="city" data-select-demo
			        data-placeholder="Выберите город" data-autosearch="true">
				<option value="" selected hidden></option>
				<option value="kaluga">Калуга</option>
				<option value="moscow">Москва</option>
				<option value="tula">Тула</option>
				<option value="tula">Тула</option>
				<option value="tula">Тула</option>
				<option value="tula">Тула</option>
				<option value="tula">Тула</option>
				<option value="tula">Тула</option>
				<option value="tula">Тула</option>
				<option value="tula">Тула</option>
				<option value="tula">Тула</option>
				<option value="tula">Тула</option>
				<option value="tula">Тула</option>
				<option value="tula">Тула</option>
				<option value="tula">Тула</option>
				<option value="tula">Тула</option>
				<option value="tula">Тула</option>
				<option value="tula">Тула</option>
				<option value="tula">Тула</option>
				<option value="tula">Тула</option>
				<option value="tula">Тула</option>
				<option value="tula">Тула</option>
				<option value="tula">Тула</option>
				<option value="tula">Тула</option>
				<option value="tula">Тула</option>
				<option value="tula">Тула</option>
				<option value="tula">Тула</option>
				<option value="tula">Тула</option>
				<option value="tula">Тула</option>
				<option value="tula">Тула</option>
				<option value="tula">Тула</option>
				<option value="tula">Тула</option>
				<option value="tula">Тула</option>
				<option value="tula">Тула</option>
				<option value="tula">Тула</option>
				<option value="tula">Липецк</option>
			</select>
			<output id="select-single-value-more" aria-live="polite">Значение: не выбрано</output>
		</div>
	</div>
</div>
JavaScript
/**
 * Описание: рабочий пример VGSelect — single.
 * Возможности: инициализация и демонстрация публичного контракта на исходном select.
 */
import {VGSelect} from 'vgapp';

function initSelectDemo() {
	const select = document.querySelector('#select-single');
	if (!select || select.dataset.inited === 'true') return;
	VGSelect.init(select); // data-* — параметры; явный запуск обязателен.
	select.addEventListener('change', () => {
		document.querySelector('#select-single-value').textContent = 'Значение: ' + (select.value || 'не выбрано');
	});

	const selectMore = document.querySelector('#select-single-more');
	if (!selectMore || selectMore.dataset.inited === 'true') return;
	VGSelect.init(selectMore); // data-* — параметры; явный запуск обязателен.
}

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;
}

Группы и недоступная опция

optgroup объединяет варианты. data-search-enabled включает поиск даже в коротком списке; data-close="false" оставляет список открытым после выбора.

HTML
<div class="select-demo">
  <label for="select-groups">Специалист</label>
  <select id="select-groups" class="vg-select" data-select-demo data-search-enabled="true" data-close="false">
    <optgroup label="Диагностика">
      <option value="ivan" selected>Иван — электрика</option>
      <option value="anna">Анна — двигатель</option>
    </optgroup>
    <optgroup label="Ремонт">
      <option value="oleg">Олег — подвеска</option>
      <option value="maria" disabled>Мария — недоступна</option>
    </optgroup>
  </select>
</div>
JavaScript
/**
 * Описание: рабочий пример VGSelect — groups.
 * Возможности: инициализация и демонстрация публичного контракта на исходном select.
 */
import {VGSelect} from 'vgapp';

function initSelectDemo() {
    const select = document.querySelector('#select-groups');
    if (!select || select.dataset.inited === 'true') return;
    VGSelect.init(select);
}

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;
}

Дерево из данных

tree: true превращает вложенные children в плоский select с визуальными отступами data-level. Это не дерево с раскрытием веток.

HTML
<div class="select-demo">
  <label for="select-tree">Категория работ</label>
  <select id="select-tree" class="vg-select" data-select-demo data-placeholder="Выберите категорию">
    <option value="" selected hidden></option>
  </select>
</div>
JavaScript
/**
 * Описание: рабочий пример VGSelect — tree.
 * Возможности: инициализация и демонстрация публичного контракта на исходном select.
 */
import {VGSelect} from 'vgapp';

function initSelectDemo() {
    const select = document.querySelector('#select-tree');
    if (!select || select.dataset.inited === 'true') return;
    VGSelect.init(select, {tree: true, search: {enabled: true}});
    VGSelect.addOptions(select, [
        {text: 'Обслуживание', children: [
            {id: 'oil', text: 'Масло'},
            {id: 'filters', text: 'Фильтры', children: [
                {id: 'air', text: 'Воздушный фильтр'},
                {id: 'cabin', text: 'Салонный фильтр'}
            ]}
        ]},
        {text: 'Диагностика', children: [{id: 'electric', text: 'Электрика'}]}
    ]);
    // Узлы без id с children недоступны для выбора; ветки не сворачиваются.
}

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;
}