what a field is called: a real label that focuses its field when pressed
npx shadcn add @ag/labelAlready installed? Preview an update
npx shadcn add @ag/label --dry-runYour installed source stays unchanged until you update it. How updates work
Latest changes · 2026-10-10
- New: what a field is called, a real
<label>, dimmed beside or around a disabled field; on glass its lettering catches the rim's light.
the demo above, verbatim
"use client"
import { Sample } from "@/app/samples"
import { Label } from "@/registry/base-nova/ui/label"
import { MaterialProvider } from "@/registry/base-nova/ui/material"
import { Textarea } from "@/registry/base-nova/ui/textarea"
// #region field
function Field({ id }: { id: string }) {
return (
<div className="flex w-72 flex-col gap-2">
<Label htmlFor={id}>note</Label>
<Textarea id={id} placeholder="anything we should know" rows={2} />
</div>
)
}
// #endregion
export default function LabelDemo() {
return (
<div className="space-y-8">
<Sample
name="materials"
title="plain and glass"
description="a press on the label focuses its field."
with="field"
>
<div className="grid gap-4 sm:grid-cols-2">
<Field id="note-plain" />
<MaterialProvider material="glass">
<div className="rounded-xl bg-[url(/lightbox/field.jpg)] bg-cover bg-center p-6">
<Field id="note-glass" />
</div>
</MaterialProvider>
</div>
</Sample>
<Sample name="note" glance title="a label over its field" with="field">
<Field id="note-alone" />
</Sample>
</div>
)
}the source, every file an install writes
"use client"
import type * as React from "react"
import { cn } from "@/lib/utils"
import { type Material, useMaterial } from "@/registry/base-nova/ui/material"
// What a field is called: a real <label>, so a press on it focuses its field (or
// wrap the field in it). The field's own voice, one step quieter than what is typed,
// at the field's size; dimmed with a disabled field beside it (`peer`) or inside it.
// `material="glass"`: lettering on glass, catching the rim's light along its foot.
export type LabelProps = React.ComponentProps<"label"> & {
material?: Material
}
export function Label({ material, className, ...props }: LabelProps) {
const m = useMaterial(material)
return (
// biome-ignore lint/a11y/noLabelWithoutControl: the consumer names its control (htmlFor) or wraps it
<label
data-slot="label"
data-material={m}
className={cn(
"inline-flex items-center gap-2 font-medium text-[13px] leading-none select-none has-[:disabled]:opacity-50 peer-disabled:opacity-50",
m === "glass"
? "text-current/90 [text-shadow:0_0.5px_0_color-mix(in_oklab,var(--glass-rim-ink,white)_40%,transparent)]"
: "text-foreground/80",
className,
)}
{...props}
/>
)
}