Label
The caption of a form control, which focuses the control when pressed.
On this page
Code
import { Input } from "@bosunkit/components/input";
import { Label } from "@bosunkit/components/label";
import { Select } from "@bosunkit/components/select";
import { Switch } from "@bosunkit/components/switch";
import { Moon, Ruler, Ship } from "lucide-react";
import { useId, useState, type CSSProperties, type Dispatch, type ReactElement, type SetStateAction } from "react";
export const description: string =
"Captions for every kind of control: a text field, a number with an icon in its caption, a long caption that " +
"wraps, a select trigger, and a switch whose caption sits beside it and turns it on and off.";
const FIELD: CSSProperties = { display: "flex", flexDirection: "column", minWidth: 0 };
const CAPTION_WITH_ICON: CSSProperties = { display: "inline-flex", alignItems: "center", gap: 6 };
export default function Showcase(): ReactElement {
const id: string = useId();
const [quietNights, setQuietNights]: [boolean, Dispatch<SetStateAction<boolean>>] = useState<boolean>(true);
return (
<div
style={{
width: "100%",
maxWidth: 560,
display: "grid",
gridTemplateColumns: "repeat(auto-fit, minmax(220px, 1fr))",
gap: "var(--space-md)",
}}
>
<div style={FIELD}>
<Label htmlFor={`${id}-name`} style={CAPTION_WITH_ICON}>
<Ship size={12} aria-hidden="true" />
Vessel name (required)
</Label>
<Input id={`${id}-name`} required defaultValue="Althea" autoComplete="off" />
</div>
<div style={FIELD}>
<Label htmlFor={`${id}-draft`} style={CAPTION_WITH_ICON}>
<Ruler size={12} aria-hidden="true" />
Draft (m)
</Label>
<Input id={`${id}-draft`} type="number" inputMode="decimal" step={0.05} defaultValue="2.10" />
</div>
<div style={FIELD}>
<Label htmlFor={`${id}-margin`}>
Margin kept under the keel when Bosun plans a passage through shallow water (m)
</Label>
<Input id={`${id}-margin`} type="number" inputMode="decimal" step={0.1} defaultValue="1.5" />
</div>
<div style={FIELD}>
<Label htmlFor={`${id}-units`}>Depth unit</Label>
<Select.Root defaultValue="m">
<Select.Trigger id={`${id}-units`}>
<Select.Value />
</Select.Trigger>
<Select.Portal><Select.Positioner alignItemWithTrigger={true} ><Select.Popup ><Select.List>
<Select.Item value="m">Meters</Select.Item>
<Select.Item value="ft">Feet</Select.Item>
<Select.Item value="fm">Fathoms</Select.Item>
</Select.List></Select.Popup></Select.Positioner></Select.Portal>
</Select.Root>
</div>
<div
style={{
gridColumn: "1 / -1",
display: "flex",
alignItems: "center",
justifyContent: "space-between",
gap: "var(--space-md)",
paddingTop: "var(--space-sm)",
borderTop: "1px solid var(--border)",
}}
>
<Label htmlFor={`${id}-quiet`} style={{ ...CAPTION_WITH_ICON, marginBottom: 0, cursor: "pointer" }}>
<Moon size={12} aria-hidden="true" />
Quiet nights: voice replies off from 22:00 to 06:00
</Label>
<Switch id={`${id}-quiet`} checked={quietNights} onCheckedChange={setQuietNights} />
</div>
</div>
);
}
A label is the caption of a form control. Its htmlFor names the control by id, so a press on the caption focuses
the control and a screen reader reads the caption as the control's name. It renders a <label> and takes its
attributes; a second press on the caption is prevented, so it does not start a text selection on it.
Examples
Label
Code
import { Input } from "@bosunkit/components/input";
import { Label as FieldLabel } from "@bosunkit/components/label";
import { useId, type ReactElement } from "react";
export const description: string = "A tap on the caption puts the cursor in the field its htmlFor names.";
export default function Label(): ReactElement {
const fieldId: string = useId();
return (
<div>
<FieldLabel htmlFor={fieldId}>Vessel name</FieldLabel>
<Input id={fieldId} />
</div>
);
}
Associate the visible name
Give the control a unique id and pass it to htmlFor. A repeated form row needs a different association for
every instance. A placeholder is an example of input, not the label; it disappears while the user types.
Keep the label concise and put format instructions in a hint associated through aria-describedby. Use
FormField when label, hint and validation need to work together. A group of related controls needs its own
legend or group name as well as labels on individual controls. Clicking the caption should focus or activate
the intended control, including in an embedded example or dialog.
Props
Also takes every attribute of ComponentProps<"label">.
Related
- Typography: the type styles a caption uses.
- Accessibility: the accessible name a control needs.