Skip to content
Component installs need the registry setup— the Base UI shadcn project, the @vegastack namespace and the Cloudflare Access service token.
VegaStack Design

Label

A styled native label for form controls — htmlFor association, disabled-dimming via peer/group, and a data-required styling hook.

Status
stable
Since
0.1.0
Accessibility pattern
native label

Last updated

Install

Add Label from the VegaStack registry. The CLI verifies the item's integrity hash before writing it.

pnpm dlx shadcn@latest add @vegastack/label

Usage

import { Label } from '@/components/ui/label';
import { Input } from '@/components/ui/input';

<Label htmlFor="email">Email</Label>
<Input id="email" type="email" />;

Label is a thin wrapper over the native <label>, so every standard attribute (htmlFor, id, onClick, …) works as expected, and its ref forwards to the underlying element. Associate it with a control by matching htmlFor to the control's id, or by wrapping the control as a child.

Examples

Required

Pass required to set a data-required="" hook on the <label>. This renders no visual asterisk — it is a styling/automation hook only, so the rendered label below looks identical to a normal one (inspect it to see the attribute). Enforce requiredness on the control itself (required / aria-required) and surface it with an inline FieldError on submit, not with a decorative mark.

Layout

Label is inline-flex by default, so it composes into running text and sits beside a control without breaking the line around itself. Pass layout="block" for the stacked form row, where the label should own its own full-width line above the input.

// Inline, in a sentence
<p>
  Type the word <Label>delete</Label> to confirm.
</p>

// Stacked above a control
<Label layout="block" htmlFor="name">Full name</Label>
<Input id="name" />

States

The label dims to 50% opacity (the --opacity-dim token) when the control it labels is disabled. Place the label after a peer control (peer-disabled:opacity-(--opacity-dim)) or inside a disabled group (group-data-[disabled=true]:opacity-(--opacity-dim)) and it reacts automatically — no extra prop needed. Both dimming paths are shown below.

Playground

Every Label prop, auto-generated from its TypeScript types.

API Reference

PropTypeDefaultDescription
layout"block" | "inline"'inline'Box layout. inline composes into running text and beside a control; block takes its own full-width line above one.
requiredbooleanfalseMarks the labelled control as required by setting data-required on the <label> (a styling/automation hook — no visual asterisk). Enforce requiredness on the control itself (required) and surface it with an inline FieldError on submit, not with a decorative mark.

Data attributes and CSS variables on Label

AttributeValues
data-layoutmirrors a prop or state value
data-required""
data-slot"label"

Accessibility

  • Form labels render at 12px (text-label-sm): a label is dense metadata ABOUT the control beneath it, not a peer of the 14px value typed into it. text-label (14px) stays for UI labels and navigation.

  • Renders a native <label> — associate it with exactly one control via htmlFor/id or by wrapping the control, so clicking the label focuses (or toggles) the control and screen readers announce the accessible name.

  • select-none keeps double-clicking the label from selecting its text instead of activating the control.

  • required sets a non-visual data-required styling hook only — it renders no asterisk or other glyph. Mark the control required (or aria-required) so the requirement is conveyed to assistive technology, and surface it on submit with an inline FieldError.

  • Disabled dimming is token-driven (peer-disabled / group-data-[disabled]) and never relies on color alone to signal state.

KeyAction
ClickFocuses (or toggles) the associated control via the label-control association.
ContractStates tested
Behaviourdefault, disabled
Accessibilitydisabled, labeled, semantic-html
Visualdefault, disabled

Do / Don't

Do
Associate every label with exactly one control via htmlFor/id (or by wrapping it), and mark the control itself required.
Don't
Use a Label without an associated control, or rely on the data-required styling hook alone — without required on the control — to convey that a field is mandatory.

On this page