Form field
Form field is a neobrutalist React component from Cruise UI. Label (with an optional Required marker), the control, a hint and an error with an icon; wires the ARIA for you. Install it with npx shadcn@latest add @cruiseui/form-field.
Install
Terminal
npx shadcn@latest add @cruiseui/form-fieldFirst time? Installation shows the one-off components.json setup (the @cruiseui registry) and how to turn the theme on.
Example
Corners
As it appears on your ID.
We'll text you when the rider leaves.
Choose your state.
"use client";
import { useState } from "react";
import { CruiseCombobox } from "@/components/cruise/combobox";
import { CruiseFormField } from "@/components/cruise/form-field";
import { CruiseInput } from "@/components/cruise/input";
import { CruiseSelect } from "@/components/cruise/select";
const states = ["Lagos", "Oyo", "Rivers", "Kano", "Enugu", "FCT"].map((label) => ({
value: label.toLowerCase(),
label,
}));
export default function FormFieldExample() {
const [name, setName] = useState("");
return (
<div className="grid gap-6 md:grid-cols-2">
<CruiseFormField
label="Full name"
required
hint="As it appears on your ID."
error={name.length === 1 ? "Enter your full name." : undefined}
>
<CruiseInput value={name} onChange={(event) => setName(event.target.value)} autoComplete="name" />
</CruiseFormField>
<CruiseFormField label="Delivery time" hint="We'll text you when the rider leaves.">
<CruiseSelect defaultValue="morning">
<option value="morning">Morning (8am – 12 noon)</option>
<option value="evening">Evening (4pm – 8pm)</option>
</CruiseSelect>
</CruiseFormField>
<CruiseFormField label="State" error="Choose your state.">
<CruiseCombobox items={states} placeholder="Search states" />
</CruiseFormField>
</div>
);
}
<div class="field">
<label class="field-label" for="name">Full name <span class="field-required">Required</span></label>
<input class="input" id="name" autocomplete="name" required aria-invalid="true" aria-describedby="name-hint name-error">
<p class="field-help" id="name-hint">As it appears on your ID.</p>
<p class="field-error" id="name-error">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" aria-hidden="true"><circle cx="12" cy="12" r="10"/><path d="M12 8v4M12 16h.01"/></svg>
<span>Enter your full name.</span>
</p>
</div>Needs theme.css. Interactive parts (menus, tabs, drawers) also need the script in the spec for that component.
When to use it
When to use
Around any form control: Input, Textarea, Select, Combobox, Naira and Phone inputs.
When not to
Checkboxes, radios and switches (they carry their own label).
Props
CruiseFormField
| Prop | Type | Default | Description |
|---|---|---|---|
label | ReactNode | — | — |
required? | boolean | false | Shows "Required" next to the label and marks the control required. |
hint? | ReactNode | — | Helper text under the control. |
error? | ReactNode | — | Error message: --danger border on the control, the message below. |
id? | string | — | The control's id (generated when left out). |
className? | string | — | — |
children | ReactNode | — | — |
Accessibility
- The label is a real <label> tied to the control's id.
- Hint and error ids go into the control's aria-describedby; an error sets aria-invalid.
- The error has an icon and words, never colour alone.