caliper uidocs

Field

Free

Wraps a control with its label, hint, error and optional action, wired for assistive tech.

Installs components/ui/field.tsxDepends on lucide-reactMotion none in component source
pnpm dlx shadcn@latest add https://caliperui.site/r/field.json

When to use #

Use it for

  • Any form control that needs a label, help text or a validation message.
  • You want errors announced when they appear.

Skip it when

  • The control is labelled by its own content, like a switch row.

Installation #

terminal
pnpm dlx shadcn@latest add https://caliperui.site/r/field.json

Adds its 3 files to components/ui/, each with its own stylesheet, and installs their packages. No account needed. The first part also adds Caliper UI’s tokens; import them once as in Installation.

Usage #

This is the code behind the preview above. It is built from Field and isEmail.

example.tsx
import { useState } from "react"
import { Field } from "@/components/ui/field"
import { Input } from "@/components/ui/input"

export function EmailField() {
  const [email, setEmail] = useState("mara@");
  const invalid = !/^\S+@\S+\.\S+$/.test(email);
  return (
    <div className="w-full max-w-xs">
      <Field label="Work email" description="We only use it to send invoices." error={invalid ? "Enter a full address, like mara@example.com." : undefined} required>
        {(control) => <Input {...control} type="email" value={email} onChange={(event) => setEmail(event.currentTarget.value)} />}
      </Field>
    </div>
  );
}

API reference #

Field

component
PropTypeDefaultDescription
label *string—
descriptionReactNode—Hint shown on the message line until a status or error replaces it.
errorstring—Replaces the hint and is announced when it appears.
statusstring—An async result such as “Checking availability…” or “Available”.
statusTone"success" | "pending""pending"
countstring—Right-aligned counter on the message line, e.g. “6 / 40”.
requiredboolean—
optionalboolean—Adds "(optional)" after the label.
actionReactNode—Something aligned with the label, such as a "Forgot password?" link.
classNamestring—
children *(props: FieldControlProps) => ReactNode—

isEmail

component

No props of its own; it accepts the native props of its root element.

Accessibility #

It is built on native elements and keeps aria-live and aria-hidden in step with state. Changes that matter are announced through a live region.

No custom key handling; Tab and the native activation keys do the work.

Motion #

It declares no animation in its component source. Any transition comes from its stylesheet, which uses the duration tokens that collapse to instant under prefers-reduced-motion.