Skip to content

Select

A fully-featured, form-associated select widget that reads native <option> and <optgroup> children, supports single and multiple selection, keyboard navigation, grouped options, and ARIA combobox semantics.

Variants

Six visual variants for different UI contexts and levels of emphasis.

PreviewCode
RTL
html
<ore-select variant="solid" placeholder="Solid">
  <option value="1">Option 1</option>
  <option value="2">Option 2</option>
</ore-select>
<ore-select variant="flat" placeholder="Flat">
  <option value="1">Option 1</option>
  <option value="2">Option 2</option>
</ore-select>
<ore-select variant="bordered" placeholder="Bordered">
  <option value="1">Option 1</option>
  <option value="2">Option 2</option>
</ore-select>
<ore-select variant="outline" placeholder="Outline">
  <option value="1">Option 1</option>
  <option value="2">Option 2</option>
</ore-select>
<ore-select variant="ghost" placeholder="Ghost">
  <option value="1">Option 1</option>
  <option value="2">Option 2</option>
</ore-select>

Colors

Six semantic colors for different contexts and validation states. Defaults to neutral when no color is specified.

PreviewCode
RTL
html
<ore-grid cols="1" cols-sm="3" cols-md="4" cols-lg="5" gap="md" style="width: 100%;">
  <ore-select variant="flat" placeholder="Default">
    <option value="1">Option 1</option>
  </ore-select>
  <ore-select variant="flat" color="primary" placeholder="Primary">
    <option value="1">Option 1</option>
  </ore-select>
  <ore-select variant="flat" color="secondary" placeholder="Secondary">
    <option value="1">Option 1</option>
  </ore-select>
  <ore-select variant="flat" color="info" placeholder="Info">
    <option value="1">Option 1</option>
  </ore-select>
  <ore-select variant="flat" color="success" placeholder="Success">
    <option value="1">Option 1</option>
  </ore-select>
  <ore-select variant="flat" color="warning" placeholder="Warning">
    <option value="1">Option 1</option>
  </ore-select>
  <ore-select variant="flat" color="error" placeholder="Error">
    <option value="1">Option 1</option>
  </ore-select>
</ore-grid>

Sizes

PreviewCode
RTL
html
<ore-select label="Small" size="sm">
  <option value="1">Option</option>
</ore-select>
<ore-select label="Medium (default)" size="md">
  <option value="1">Option</option>
</ore-select>
<ore-select label="Large" size="lg">
  <option value="1">Option</option>
</ore-select>

Label Placement

PreviewCode
RTL
html
<ore-select label="Inset label (default)" label-placement="inset">
  <option value="">Select…</option>
  <option value="a">Alpha</option>
</ore-select>
<ore-select label="Outside label" label-placement="outside">
  <option value="">Select…</option>
  <option value="a">Alpha</option>
</ore-select>

Grouped Options

Use native <optgroup> elements to create labelled groups. For lists longer than ~8 options, grouping improves scanability.

PreviewCode
RTL
html
<ore-select label="Fruit or Vegetable">
  <optgroup label="Fruits">
    <option value="apple">Apple</option>
    <option value="banana">Banana</option>
    <option value="cherry">Cherry</option>
  </optgroup>
  <optgroup label="Vegetables">
    <option value="carrot">Carrot</option>
    <option value="broccoli">Broccoli</option>
  </optgroup>
</ore-select>

Multiple Selection

Add multiple to allow selecting more than one option. Each selected value is displayed as a removable ore-chip tag inside the trigger field — clicking the × on a chip deselects that value without closing the dropdown. Only use multiple for selections where more than one value logically makes sense.

PreviewCode
RTL
html
<ore-select label="Skills" multiple color="primary">
  <option value="ts">TypeScript</option>
  <option value="rust">Rust</option>
  <option value="go">Go</option>
  <option value="python">Python</option>
  <option value="java">Java</option>
</ore-select>

The change event detail includes both value (comma-separated string) and values (array of selected values):

js
document.querySelector('ore-select').addEventListener('change', (e) => {
  console.log('csv:', e.detail.value); // "ts,rust"
  console.log('array:', e.detail.values); // ["ts", "rust"]
});

Helper & Error Text

Combine required with error text to give users clear validation feedback.

PreviewCode
RTL
html
<ore-select label="Role" helper="Choose the role that best fits.">
  <option value="">Select a role…</option>
  <option value="admin">Admin</option>
  <option value="editor">Editor</option>
  <option value="viewer">Viewer</option>
</ore-select>

<ore-select label="Priority" error="Please select a priority." color="error">
  <option value="">Select…</option>
  <option value="high">High</option>
  <option value="medium">Medium</option>
</ore-select>

States

PreviewCode
RTL
html
<ore-select label="Disabled select" disabled>
  <option value="1">Option</option>
</ore-select>
<ore-select label="Required select" required>
  <option value="">Choose…</option>
  <option value="a">Alpha</option>
</ore-select>

Loading State

Set loading to show a loading indicator inside the dropdown while options are being fetched from a server. The option list is hidden during loading.

PreviewCode
RTL
html
<ore-select label="Country" loading></ore-select>
js
const select = document.querySelector('ore-select');
select.loading = true;
const data = await fetch('/api/countries').then((r) => r.json());
select.options = data.map((c) => ({ value: c.code, label: c.name }));
select.loading = false;

JavaScript Options

For dynamic or large option lists, set the options property directly in JavaScript instead of using <option> children. Each item only needs a value; label falls back to the same string when omitted, and group remains optional.

js
const select = document.querySelector('ore-select');
select.options = [
  { value: 'us', label: 'United States' },
  { value: 'gb', label: 'United Kingdom', group: 'Europe' },
  { value: 'de', label: 'Germany', group: 'Europe' },
  { value: 'fr', label: 'France', group: 'Europe' },
];

Assigning a new array to options at any time updates the dropdown immediately. When both <option> children and options are provided, the JS property takes precedence.

In a Form

ore-select is form-associated. Read the value via FormData or a change event. Supply a placeholder <option value="">…</option> when the field is not pre-selected.

html
<ore-form id="myForm">
  <ore-select name="category" label="Category" required>
    <option value="">Select a category…</option>
    <option value="tech">Technology</option>
    <option value="science">Science</option>
    <option value="art">Art</option>
  </ore-select>
  <ore-button type="submit">Submit</ore-button>
</ore-form>

<script type="module">
  import '@vielzeug/refine/form';
  import '@vielzeug/refine/select';
  import '@vielzeug/refine/button';

  document.getElementById('myForm').addEventListener('submit', (e) => {
    e.preventDefault();
    const data = new FormData(e.target);
    console.log('category:', data.get('category'));
  });

  document.querySelector('ore-select').addEventListener('change', (e) => {
    console.log('Selected value:', e.detail.value);
    console.log('Selected labels:', e.detail.labels);
    // For multiple: e.detail.values (string[])
  });

  document.querySelector('ore-select').addEventListener('open', (e) => {
    console.log('Opened because:', e.detail.reason); // 'trigger' | 'programmatic'
  });

  document.querySelector('ore-select').addEventListener('close', (e) => {
    console.log('Closed because:', e.detail.reason); // 'escape' | 'outside-click' | 'programmatic' | 'trigger'
  });
</script>

API Reference

Attributes

AttributeTypeDefaultDescription
valuestring''Currently selected value
namestring''Form field name
labelstring''Label text
label-placement'inset' | 'outside''inset'Label positioning
placeholderstring''Empty-state placeholder text
helperstring''Helper text shown below the control
errorstring''Error message; overrides helper text
variant'solid' | 'flat' | 'bordered' | 'outline' | 'ghost''solid'Visual style variant
color'default' | 'primary' | 'secondary' | 'success' | 'warning' | 'error' | 'info''default'Color theme
size'sm' | 'md' | 'lg''md'Control size
multiplebooleanfalseAllow multiple selections
disabledbooleanfalseDisable the control
requiredbooleanfalseMark field as required for form validation
fullwidthbooleanfalseExpand to full width
rounded'none' | 'sm' | 'md' | 'lg' | 'full'Override border-radius
loadingbooleanfalseShow loading indicator in the dropdown

Slots

SlotDescription
(default)<option> and <optgroup> elements to display

Events

EventDetailDescription
change{ value: string, values: string[], labels: string[], originalEvent?: Event }Emitted when the selected value(s) change
open{ reason: 'trigger' | 'programmatic' }Emitted when the dropdown opens
close{ reason: 'escape' | 'outside-click' | 'programmatic' | 'trigger' }Emitted when the dropdown closes

CSS Custom Properties

PropertyDescriptionDefault
--select-border-colorDefault border color--color-border
--select-focus-colorFocus ring / active colorPer color theme
--select-bgTrigger backgroundPer variant
--select-dropdown-bgDropdown panel background--color-surface
--select-option-hover-bgOption hover state background--color-hover
--select-heightTrigger heightPer size

Accessibility

The select component follows WCAG 2.1 Level AA standards.

The trigger uses role="combobox" with aria-haspopup="listbox", aria-expanded, and aria-activedescendant. The dropdown uses role="listbox"; each option uses role="option" with aria-selected; aria-multiselectable is set when multiple is active. aria-labelledby links the label; aria-describedby links helper and error text. aria-disabled reflects the disabled state.

Keyboard navigation is fully supported: Tab focuses the trigger; Enter or Space opens the dropdown. Arrow keys navigate options; Home and End jump to the first and last option; Escape closes the dropdown; Tab closes and moves focus out.