Name any control with a label, and let a press on the label reach it.
A plain <label> only reaches inputs, buttons and selects. Label names any control by its for, including a radio group or a slider, and a press on the label moves focus into it.
import { Label } from "@ui-sdk/solid/label"
import { Radio, RadioGroup, RadioIndicator } from "@ui-sdk/solid/radio"
import { For } from "solid-js"
const speeds = [
{ value: "standard", label: "Standard" },
{ value: "express", label: "Express" },
{ value: "overnight", label: "Overnight" },
]
function Example() {
return (
<div data-slot="stack">
<Label for="shipping-speed">Shipping speed</Label>
<RadioGroup id="shipping-speed" defaultValue="standard">
<For each={speeds}>
{(speed) => (
<Label>
<Radio value={speed.value}>
<RadioIndicator />
</Radio>
{speed.label}
</Label>
)}
</For>
</RadioGroup>
</div>
)
}
export { Example }Installation
npm install @ui-sdk/solid @ui-sdk/coreUsage
Import the label and point its for at the control's id:
import { Label } from "@ui-sdk/solid/label"
import { Radio, RadioGroup } from "@ui-sdk/solid/radio"
function Plan() {
return (
<>
<Label for="plan">Plan</Label>
<RadioGroup id="plan" defaultValue="pro">
<Radio value="free">Free</Radio>
<Radio value="pro">Pro</Radio>
</RadioGroup>
</>
)
}
export { Plan }Label renders a native <label>. When the browser can reach the control on its own, like an input, it does. For anything else, the control takes the label as its name, and a press on the label focuses it, checks it or clicks it, as a native label would.
Inside a Field, use FieldLabel, which also ties the field's description and errors to the control.
Build Your Own
@ui-sdk/solid/label comes with a ready-made Label. If you'd like to build your own, with your own name, start from the label primitive in @ui-sdk/core:
import { label } from "@ui-sdk/core/label"
import { createParts } from "@ui-sdk/solid/primitive"
const { Root: Caption } = createParts(label, { root: "label" })
export { Caption }<Caption for="plan">Plan</Caption>Caption keeps the behavior of the ready-made Label: it names the control and reaches it on a press. See Rendering and Custom Parts for more.
Slider
A label for a slider names its thumb, so the thumb reads as Volume, and a press on the label focuses it.
import { Label } from "@ui-sdk/solid/label"
import {
Slider,
SliderControl,
SliderIndicator,
SliderThumb,
SliderTrack,
SliderValue,
} from "@ui-sdk/solid/slider"
function Example() {
return (
<Slider id="volume" defaultValue={75}>
<div data-slot="row">
<Label for="volume">Volume</Label>
<SliderValue />
</div>
<SliderControl>
<SliderTrack>
<SliderIndicator />
<SliderThumb />
</SliderTrack>
</SliderControl>
</Slider>
)
}
export { Example }Switch
Point the label at a switch beside it. A press on the label turns the switch on and off.
import { Label } from "@ui-sdk/solid/label"
import { Switch, SwitchThumb } from "@ui-sdk/solid/switch"
function Example() {
return (
<div data-slot="row">
<Switch id="updates">
<SwitchThumb />
</Switch>
<Label for="updates">Email me product updates</Label>
</div>
)
}
export { Example }Wrapping a Control
Put the control inside the label instead of pointing at it, and you need no id.
import { Checkbox, CheckboxIndicator } from "@ui-sdk/solid/checkbox"
import { Label } from "@ui-sdk/solid/label"
function Example() {
return (
<Label>
<Checkbox>
<CheckboxIndicator>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
aria-hidden="true"
>
<path d="M20 6 9 17l-5-5" />
</svg>
</CheckboxIndicator>
</Checkbox>
Accept terms and conditions
</Label>
)
}
export { Example }Custom Rendering
Pass render to use a different element, such as render={(props) => <span {...props} />}. A label that isn't a <label> still names its control and reaches it on a press. See Parts and Composition for more.
Styling
The label is unstyled. It has a data-slot of label.
A double click on the label doesn't select its text, so you don't need user-select: none for that.
API Reference
Props are the same as below, as Solid props, along with a native label's for.
Label
debug?boolean- Logs every state change with its reason to the console, in development builds.
Accessibility
A native <label> names the element its for points at only when that element is labelable, like an input or a button. Label names any other control through aria-labelledby, unless the control has an aria-label or an aria-labelledby of its own, which win. Its press does what a native label's does: it checks a checkbox, a switch or a radio, focuses a group's checked radio, and focuses anything else. A press on a disabled control does nothing.
Tested Behavior
Every line below is an automated test.
- A label names a native input, and a press focuses it.
- A label names a radio group, and a press focuses its checked radio.
- A label for a slider names its thumb, and a press focuses it.
- A label around a checkbox names it, and a press toggles it.
- A press on the label of a disabled group moves no focus.
- A control its author names keeps that name.
- A label names a control that renders after it.
- A double click on a label doesn't select its text.
Runs in React, Vue and web components.