Label

An accessible label component built on Radix UI Label that associates text with form controls via htmlFor or by wrapping the control element. Supports peer-disabled styling to visually mute the label when its paired input is disabled.

Installation

npm install @designforge/ui

Usage

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

Examples

Basic Label

A simple label rendered as a standalone element.

<Label>Email address</Label>

With Input via htmlFor

Use the htmlFor prop to associate the label with an input by matching the input's id.

import { Label } from "@/components/ui/label"
import { Input } from "@/components/ui/input"
 
export function LabelWithInput() {
  return (
    <div className="flex flex-col gap-1.5">
      <Label htmlFor="email">Email address</Label>
      <Input id="email" type="email" placeholder="you@example.com" />
    </div>
  )
}

Wrapping a Checkbox

Wrap the control element directly inside the label to create an implicit association without needing htmlFor or id.

import { Label } from "@/components/ui/label"
import { Checkbox } from "@/components/ui/checkbox"
 
export function LabelWrappingCheckbox() {
  return (
    <Label className="flex items-center gap-2 cursor-pointer">
      <Checkbox />
      Accept terms and conditions
    </Label>
  )
}

Disabled State

When the paired input is disabled, the peer-disabled utility makes the label appear visually muted, signalling that the field is not interactive.

import { Label } from "@/components/ui/label"
import { Input } from "@/components/ui/input"
 
export function LabelDisabledState() {
  return (
    <div className="flex flex-col gap-1.5">
      <Label htmlFor="disabled-input">Username</Label>
      <Input
        id="disabled-input"
        disabled
        defaultValue="mayank_dev"
        className="peer"
      />
    </div>
  )
}

Required Indicator

Add a visual asterisk to communicate that a field is required.

import { Label } from "@/components/ui/label"
import { Input } from "@/components/ui/input"
 
export function LabelRequired() {
  return (
    <div className="flex flex-col gap-1.5">
      <Label htmlFor="full-name">
        Full name <span className="text-destructive">*</span>
      </Label>
      <Input id="full-name" placeholder="Jane Doe" required />
    </div>
  )
}

API Reference

Label

Renders a <label> element with accessible styling. Accepts a forwarded ref and all standard HTML label attributes.

PropTypeDefaultDescription
htmlForstringThe id of the form control this label describes.
classNamestringAdditional CSS classes merged via cn.
refReact.Ref<HTMLLabelElement>Forwarded ref attached to the underlying <label> element.

All other standard HTML <label> attributes (e.g., onClick, style, aria-*) are forwarded to the underlying element.

Accessibility

  • Rendered as a native <label> element, giving it full browser and assistive-technology support out of the box.
  • When htmlFor matches a control's id, clicking the label focuses the control — this behaviour is provided by the browser natively.
  • Wrapping the control inside the label creates an implicit association, which is equally valid and avoids the need for matching id/htmlFor pairs.
  • The peer-disabled:cursor-not-allowed peer-disabled:opacity-70 classes visually communicate the disabled state so that users who rely on visual cues understand the field is not interactive, without hiding it from screen readers.
  • Always provide a label for every form control. Do not rely solely on placeholder text as a substitute for a visible label.

Live View

Open in Storybook ↗