Qure UI
Components

Label

Names a form control.

import { Input } from '@/registry/qure/ui/input'import { Label } from '@/registry/qure/ui/label'export default function LabelDemo() {  return (    <div className="grid w-full max-w-xs gap-2">      <Label htmlFor="accession">Accession number</Label>      <Input id="accession" placeholder="ACC-000000" />    </div>  )}

Installation

npx shadcn@latest add https://qure-ui.qure.ai/r/label.json

Usage

import { Label } from '@/components/ui/label'

Either associate it explicitly, or wrap the control:

<Label htmlFor="accession">Accession number</Label>
<Input id="accession" />

<Label><Checkbox /> Include prior studies</Label>

Both make the text a click target for the control, which matters more than it sounds — a 14px checkbox is a small thing to hit, and the label is usually ten times the area.

A Label is for a form control and nothing else. Text that names a region, a card or a table column is a heading or a th; giving it a label element points the accessibility tree at a control that does not exist.

Beside an input

import { Input } from '@/registry/qure/ui/input'import { Label } from '@/registry/qure/ui/label'export default function LabelDemo() {  return (    <div className="grid w-full max-w-xs gap-2">      <Label htmlFor="accession">Accession number</Label>      <Input id="accession" placeholder="ACC-000000" />    </div>  )}

The default shape: label above, control below, an 8px gap. Use htmlFor with the control's id whenever the two are siblings rather than nested.

Wrapping a control

import { Checkbox } from '@/registry/qure/ui/checkbox'import { Label } from '@/registry/qure/ui/label'import { Switch } from '@/registry/qure/ui/switch'export default function LabelControl() {  return (    <div className="flex w-full max-w-xs flex-col gap-3">      <Label>        <Checkbox defaultChecked /> Include prior studies      </Label>      <Label>        <Switch /> Auto-refresh the worklist      </Label>    </div>  )}

For a checkbox or a switch, wrapping is usually better than htmlFor — there is no id to keep in step, and the whole row becomes the hit target. Label is already inline-flex items-center gap-2, so the control and its text align without extra classes.

Both forms work with Base UI's Checkbox and Switch: each renders a real hidden input beside the visible span, and their id prop lands on that input rather than on the span — so htmlFor associates correctly. Set nativeButton and the id moves to the span, at which point only wrapping works.

Required and optional

import { Input } from '@/registry/qure/ui/input'import { Label } from '@/registry/qure/ui/label'export default function LabelRequired() {  return (    <div className="grid w-full max-w-xs gap-4">      <div className="grid gap-2">        <Label htmlFor="mrn">          MRN <span aria-hidden className="text-[var(--text-urgent-default)]">*</span>        </Label>        <Input id="mrn" required placeholder="MRN-0000000" />      </div>      <div className="grid gap-2">        <Label htmlFor="referrer" className="w-full justify-between">          Referring clinician          <span className="font-normal text-muted-foreground">Optional</span>        </Label>        <Input id="referrer" placeholder="Dr A. Deshpande" />      </div>    </div>  )}

Mark whichever is rarer, and mark it once. The asterisk is aria-hidden because the control's own required attribute is what a screen reader announces — a read-out "star" adds noise. Where most fields are required, label the exceptions "Optional" instead and drop the asterisks.

A placeholder is not a label. It disappears exactly when someone needs it, it is announced inconsistently, and it fails contrast far more often than body text. Every input wants a real label, even when the design puts it visually elsewhere. If the design has no room, keep the label and hide it with sr-only.

API Reference

No primitive and no added props — everything a native <label> accepts, including htmlFor. Inside a Base UI Field the association is supplied for you and htmlFor becomes unnecessary.

The stylesheet greys the label when the control it names is disabled, via :has(+ :disabled) and :has(:disabled) — so the sibling and wrapping forms both dim without a prop.

On this page