@cf/label
Label
A styled <label> for naming a form control when you're not using Field.
Clicking the first label toggles its switch. The second switch is disabled, and its label doesn't dim yet: Base UI renders the switch root as a span, which never matches :disabled, so peer-disabled: has nothing to catch.
A plain <label> with type styles. It exists mostly because FieldLabel is built on it, and I reach for FieldLabel in almost every case. Nothing on the site imports Label directly.
The peer-disabled: classes only work for a control that is an earlier sibling marked peer. That rules out both of the controls people reach for: Input isn't marked peer, and Switch renders a span, which never matches :disabled. Dim the Label yourself when its control is disabled.
import { Label } from "@/components/ui/label";
<Label htmlFor="name">Name</Label>
<input id="name" />Rules
The same rules ship in DESIGN.md and the MCP server, for the agents building with this.
- must
Set
htmlForto the control'sid, or wrap the control inside the Label; a Label with neither names nothing.The component just forwards
htmlFor, so the association is entirely the caller's job.associate-with-control
- should
Inside a
Field, useFieldLabelinstead of Label, so the label picks up the field's disabled and checked states.prefer-field-label
- may
Rely on the built-in
peer-disableddimming only when the control comes before the Label in the DOM and is a native input carrying thepeerclass;:disablednever matches Base UI'sSwitch, which renders aspan.peer-disabled-needs-order
Install
bunx shadcn@latest add @cf/labelNeeds the @cf registry in your components.json once. The theme and any sibling components come along automatically.
Source
label.tsxShowHide
"use client";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "cn";
import * as React from "react";
const labelVariants = cva(
"font-medium text-sm leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
);
type LabelProps = React.ComponentProps<"label"> &
VariantProps<typeof labelVariants>;
const Label = React.forwardRef<HTMLLabelElement, LabelProps>(
({ className, htmlFor, ...props }, ref) => (
// biome-ignore lint/a11y/noLabelWithoutControl: This reusable wrapper forwards the consumer-provided control association.
<label
className={cn(labelVariants(), className)}
htmlFor={htmlFor}
ref={ref}
{...props}
/>
)
);
Label.displayName = "Label";
export { Label, type LabelProps, labelVariants };