Select
A custom listbox-style select, with optional grouped options.
fandry-select
Example
Link to section ExampleCustom colors and parts
Link to section Custom colors and partsThe same component with a few --fd-* tokens set around it and its parts restyled. The code is under Parts below.
Props
Link to section Props| Prop | Type | Default | Description |
|---|---|---|---|
label | string | '' | Visible label. |
placeholder | string | '' | Shown when nothing is selected. |
options | { label, value, disabled?, component?, componentProps? }[] | [] | Flat option list. An option's component (with componentProps) draws its own row instead of the label -- see the custom options example. |
groups | { label, options }[] | [] | Grouped option list (used instead of options). |
value | string | '' | Selected value. '' (or null) is no selection and shows the placeholder, unless an option has that value: give one value: '' to offer "None". |
change (event) | CustomEvent<string> | — | Fires when the user picks a different value; event.detail is the new value. Not fired when value is set from code. |
help-text | string | '' | Helper text below the field. |
error-text | string | '' | An error shown under the field: the field is invalid while it has one (aria-invalid, the invalid state), and a screen reader hears it when it appears and when the field is focused. |
label · help-text · error-text (slots) | slot | the props | Markup in place of the label, help text or error text. Shown even without the matching prop. |
Parts
Link to section PartsStyle the elements inside the component from your own CSS with ::part(). Every fandry component renders in native shadow DOM, so parts work on LWR and Salesforce alike. For colors, spacing, radius and type across many components, set the --fd-* tokens instead. The code for the "Custom colors and parts" example above:
| Part | Description |
|---|---|
base | The outermost element. |
label | The label. |
required | The required-field asterisk. |
control | The box the field draws: a text field's border, a select's button, a checkbox's box, a radio's circle, a switch's track. |
value | The selected value, as shown in the closed field. |
chevron | The dropdown arrow. |
listbox | The list of options. |
option | One option. |
group | A group of options. |
group-label | A group's heading. |
help-text | The help text under the field. |
error-text | The error under the field. In the page even while empty, so style it only for a field that is invalid. |
panel | The surface that opens: a dropdown's list, a popover, a tooltip, a dialog, a loading overlay's box. |
States are extra names on a part while the state is on. Name both to style one state, e.g.fandry-checkbox::part(control checked).
| State | Description |
|---|---|
disabled | A control, option or item that cannot be used. |
invalid | A field that has error text. |
selected | The chosen option, a selected table row, or the selected tab. |
active | The option the keyboard or pointer is on. |
<!-- template -->
<div class="brand narrow">
<fandry-select label="Size" placeholder="Choose a size" options={options} value="m"></fandry-select>
</div>
/* css */
/* Scoped to this demo. Set the same --fd-* tokens on :root to theme
every fandry-* component on the site. */
.brand {
--fd-radius-md: 0.75rem;
--fd-border-focus: 160 84% 36%;
--fd-ring-color: 160 84% 36%;
--fd-bg-muted: 160 40% 94%;
}
fandry-select::part(control) {
background: hsl(160 40% 98%);
font-weight: 600;
}
fandry-select::part(panel) {
box-shadow: 0 12px 32px hsl(160 40% 20% / 0.18);
}
fandry-select::part(option) {
padding-block: 0.5rem;
}
/* A state: only the chosen option. */
fandry-select::part(option selected) {
font-weight: 700;
color: hsl(160 84% 26%);
}
Code
Link to section Code<fandry-select
label="Plan"
placeholder="Choose a plan"
options={planOptions}
value="pro"
></fandry-select>
Example: Custom options
Link to section Example: Custom optionsCode
<!-- template -->
<fandry-select label="Plan" options={planOptions}
value={value} onchange={handleChange}></fandry-select>
// component
import PlanRow from 'my/planRow'; // your LWC: @api icon, label, hint
planOptions = [
{
label: 'Free', value: 'free', component: PlanRow,
componentProps: { icon: '🌱', label: 'Free' }
},
{
label: 'Pro', value: 'pro', component: PlanRow,
componentProps: { icon: '💎', label: 'Pro', hint: 'Popular' }
},
{ label: 'Enterprise', value: 'enterprise', disabled: true } // plain option
];
// The component draws only the inside of the row; the row keeps its
// highlight, hover, keyboard and click, and `label` stays the accessible
// name and what typeahead matches, so give every option a real one.
// The chosen option's component is also shown in the closed control.
//
// On Salesforce this uses lwc:is: fandry-select's .js-meta.xml needs the
// lightning__dynamicComponent capability (API 55+), which `fandry add` writes.
Example: A long list, with the keyboard
Link to section Example: A long list, with the keyboardCode
<!-- template -->
<fandry-select label="Country" placeholder="Choose a country"
options={countryOptions} value={value} onchange={handleChange}></fandry-select>
// component
handleChange(event) {
this.value = event.detail;
}
// The list scrolls once it is taller than --fd-listbox-max-height, and
// the option the keyboard is on is kept in view. Hovering never scrolls.
//
// Closed: Enter, Space, ArrowDown or ArrowUp open the list
// ArrowLeft / ArrowRight choose the previous or next option
// typing chooses the option that starts with what was typed
// Open: ArrowUp / ArrowDown move, and stop at the first and last option
// Home / End, Page Up / Page Down move further
// typing moves to a match: "new z" finds New Zealand, and "s"
// pressed again steps through the options that start with s
// Enter or Space choose; Escape or Tab close without choosing