Select With Extras
SelectWithExtras is a headless enhanced select component that wraps a native <select> element with optional content areas before and after it. This allows consumers to place supplementary elements such as icons, flags, status indicators, or helper text alongside the select without breaking its accessibility.
Use SelectWithExtras when you need a native select dropdown with additional visual context. For example, displaying a country flag before a country selector, showing a unit label after a measurement selector, or adding an icon before a category picker. The component preserves full native select behavior including keyboard navigation, form submission, and screen reader support.
Example
Show demo markup
<div class="select-with-extras"><input type="text" aria-label="Filter options" placeholder="Search..." /><select aria-label="Choose an option"><option>Option 1</option><option>Option 2</option></select></div>
Usage example
<script lang="ts">
import SelectWithExtras from "./SelectWithExtras.svelte";
let country = $state("us");
</script>
<SelectWithExtras label="Country" bind:value={country}>
{#snippet before()}<span aria-hidden="true">🇺🇸</span>{/snippet}
<option value="us">United States</option>
<option value="gb">United Kingdom</option>
</SelectWithExtras>
Show Svelte source
// In your Svelte component:
import SelectWithExtras from "lily-design-system-svelte-headless/components/SelectWithExtras/SelectWithExtras.svelte";
<SelectWithExtras>
<!-- content -->
</SelectWithExtras>
Usage
Country selector with a flag icon before the select:
<SelectWithExtras label="Country" value={country}>
{#snippet before()}<span class="flag-icon">🏳</span>{/snippet}
<option value="us">United States</option>
<option value="uk">United Kingdom</option>
<option value="fr">France</option>
</SelectWithExtras>
Currency selector with symbol after the select:
<SelectWithExtras label="Currency" value={currency}>
<option value="GBP">British Pound</option>
<option value="USD">US Dollar</option>
<option value="EUR">Euro</option>
{#snippet after()}<span class="currency-symbol">£</span>{/snippet}
</SelectWithExtras>
Unit selector with a label before:
<SelectWithExtras label="Measurement unit" value={unit}>
{#snippet before()}<span>Unit:</span>{/snippet}
<option value="kg">Kilograms</option>
<option value="lb">Pounds</option>
</SelectWithExtras>
Props
label: string (required) -- accessible label for the select element, applied via aria-label
value: string (default: "") -- the currently selected value; two-way bindable via value
required: boolean (default: false) -- whether the select is required for form validation
disabled: boolean (default: false) -- whether the select is disabled
children: slot (required) -- <option> elements for the select
before: slot (optional) -- content rendered before the select element
after: slot (optional) -- content rendered after the select element
...restProps: unknown -- additional attributes spread onto the wrapper <div> element
Keyboard Interactions
- Tab: Moves focus to the native select element
- Arrow Up / Arrow Down: Navigates between options (native select behavior)
- Space / Enter: Opens the select dropdown on some platforms (native select behavior)
- Escape: Closes the dropdown if open (native select behavior)
ARIA
aria-label={label} -- provides an accessible name for the select element so screen readers announce its purpose
When to Use
- Use SelectWithExtras when a native select dropdown needs supplementary visual context such as icons, flags, or unit labels alongside the options.
- Use SelectWithExtras to preserve full native select behavior (keyboard navigation, form submission, screen reader support) while adding decorative elements.
- Use SelectWithExtras for country selectors with flag icons, currency selectors with symbols, or unit selectors with labels.
- Use SelectWithExtras when the before/after content is purely decorative or informational.
When Not to Use
- Do not use SelectWithExtras when a native Select without extra visual context is sufficient.
- Do not use SelectWithExtras for free-text search or filterable dropdowns -- use Combobox instead.
- Do not use SelectWithExtras when the before/after content is interactive -- interactive elements in these slots can confuse keyboard navigation.
Headless
This headless component provides the semantic structure of a native <select> element wrapped in a container with optional before/after slots, along with proper aria-label for accessibility. The consumer provides all visual styling for the wrapper, the select element, and any supplementary content placed in the before/after slots.
Styles
The consumer provides all CSS styling. The component renders with a .select-with-extras class for targeting. No default styles are included — this is a fully headless component.
Testing
- Verify the component renders a
<div> element with class select-with-extras
- Verify aria-label={label}` -- provides an accessible name for the select element so screen readers announce its purpose
- Verify keyboard interactions work correctly
- Verify pass-through attributes are applied
Advice
- Designers: Keep before/after content compact so it does not visually overwhelm the select control. Use consistent icon sizes and spacing across all SelectWithExtras instances.
- Developers: Ensure the
before and after slot content is decorative or supplementary only; interactive elements in these slots can confuse keyboard navigation. Use the aria-label prop rather than relying on before/after content for accessible naming.
Implementation Notes
- Renders a wrapper
<div> containing optional before slot, a native <select>, and optional after slot
- The
<select> element receives aria-label for accessibility, with two-way binding
- Supports
required and disabled attributes on the native select
- Supports two-way binding for the
value prop, enabling two-way value binding from the parent
- The
before and after slots are conditionally rendered only when provided
- Spreads
restProps onto the wrapper div for consumer customization
Related components
select — a dropdown select element for choosing one option
combobox — a text input combined with a dropdown list for filtering options
cascader — a multi-level dropdown for selecting a value from a hierarchy
References
- WAI-ARIA Listbox Pattern: https://www.w3.org/WAI/ARIA/apg/patterns/listbox/
- HTML
<select> element: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/select
Canonical contract
Generated from this component's canonical metadata — the machine-checked source the implementations are held to.
Metadata
- Component: select-with-extras
- PascalCase: SelectWithExtras
- Description: a select dropdown with additional features like search or groups
- Status: beta — implemented and unit-tested in all seven frameworks with an axe-clean demo page; not yet exercised in composed flows
- HTML tag: <div>
- CSS class: .select-with-extras
- Interactive: yes
ARIA
aria-label={label} -- provides an accessible name for the select element so screen readers announce its purpose
Keyboard
- Tab: Moves focus to the native select element
- Arrow Up / Arrow Down: Navigates between options (native select behavior)
- Space / Enter: Opens the select dropdown on some platforms (native select behavior)
- Escape: Closes the dropdown if open (native select behavior)
Props
label: string (required) -- accessible label for the select element, applied via aria-label value: string (default: "") -- the currently selected value; two-way bindable via value required: boolean (default: false) -- whether the select is required for form validation disabled: boolean (default: false) -- whether the select is disabled children: slot (required) -- <option> elements for the select before: slot (optional) -- content rendered before the select element after: slot (optional) -- content rendered after the select element ...restProps: unknown -- additional attributes spread onto the wrapper <div> element