caliper uidocs

Input

Free

A recessed text field with optional leading and trailing affixes; it never jumps when validation appears.

Installs components/ui/input.tsxDepends on none beyond ReactMotion none in component source
pnpm dlx shadcn@latest add https://caliperui.site/r/input.json
caliper.app/

When to use #

Use it for

  • Names, emails, search terms and any short free text.
  • Pair it with a label, or wrap it in a field.

Skip it when

  • The value is a number with steps; use a number field.
  • The text is long; use a textarea.

Installation #

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

Adds its 2 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.

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

export function EmailInput() {
  const taken = ["halden", "ostra", "atlas", "lumen", "admin"];
  const [slug, setSlug] = useState("halden");
  const [checking, setChecking] = useState(false);
  const format = /^[a-z0-9-]*$/.test(slug);
  const error = !format ? "Use lowercase letters, numbers and hyphens only." : !checking && taken.includes(slug) ? `${slug} is taken. Try ${slug}-team or ${slug}-hq.` : undefined;
  const ok = format && slug.length >= 3 && !checking && !taken.includes(slug);
  return (
    <div className="w-full max-w-sm">
      <Field
        label="Workspace URL"
        description="Lowercase letters, numbers and hyphens. 3 to 32 characters."
        error={error}
        status={checking ? "Checking availability…" : ok ? `caliper.app/${slug} is available.` : undefined}
        statusTone={checking ? "pending" : "success"}
        count={`${slug.length} / 32`}
      >
        {(control) => (
          <Input
            {...control}
            leading="caliper.app/"
            autoComplete="off"
            spellCheck={false}
            maxLength={32}
            value={slug}
            onChange={(event) => {
              const next = event.currentTarget.value;
              setSlug(next);
              setChecking(true);
              window.setTimeout(() => setChecking(false), 450);
            }}
          />
        )}
      </Field>
    </div>
  );
}

API reference #

Input

component

Also accepts the native props of its root element and a ref.

PropTypeDefaultDescription
leadingReactNode—Fixed text or an icon before the value, e.g. "caliper.app/".
trailingReactNode—Text, an icon or a status after the value, e.g. a spinner or a count.

Accessibility #

It is built on native elements, so roles and focus come from the browser.

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.