Components
- Accordion
- Alert
- Alert Dialog
- Autocomplete
- Avatar
- Badge
- Breadcrumb
- Button
- Card
- Checkbox
- Checkbox Group
- Collapsible
- Combobox
- Dialog
- Field
- Fieldset
- Form
- Frame
- Group
- Input
- Label
- Menu
- Meter
- Number Field
- Pagination
- Popover
- Preview Card
- Progress
- Radio Group
- Scroll Area
- Select
- Separator
- Sheet
- Slider
- Switch
- Table
- Tabs
- Textarea
- Toast
- Toggle
- Toggle Group
- Toolbar
- Tooltip
Resources
Field
A component that provides labelling and validation for form controls.
Visible on your profile
import {
Field,
FieldControl,
FieldDescription,
FieldLabel,
} from "@/components/ui/field"
export function FieldDemo() {
return (
<Field>
<FieldLabel>Name</FieldLabel>
<FieldControl type="text" placeholder="Enter your name" />
<FieldDescription>Visible on your profile</FieldDescription>
</Field>
)
}
Installation
pnpm dlx shadcn@latest add https://coss.com/ui/r/field.json
Usage
import {
Field,
FieldControl,
FieldDescription,
FieldError,
FieldLabel,
FieldValidity,
} from "@/components/ui/field"
<Field>
<FieldLabel>Name</FieldLabel>
<FieldControl type="text" placeholder="Enter your name" />
<FieldDescription>Visible on your profile</FieldDescription>
<FieldError>Please enter a valid name</FieldError>
<FieldValidity>
{(validity) => (
{validity.error && <p>{validity.error}</p>}
)}
</FieldValidity>
</Field>
Examples
Required Field
import {
Field,
FieldControl,
FieldError,
FieldLabel,
} from "@/components/ui/field"
export function FieldRequiredDemo() {
return (
<Field>
<FieldLabel>
Password <span className="text-destructive-foreground">*</span>
</FieldLabel>
<FieldControl type="password" placeholder="Enter password" required />
<FieldError>Please fill out this field.</FieldError>
</Field>
)
}
Disabled Field
This field is currently disabled.
import {
Field,
FieldControl,
FieldDescription,
FieldLabel,
} from "@/components/ui/field"
export function FieldDisabledDemo() {
return (
<Field disabled>
<FieldLabel>Email</FieldLabel>
<FieldControl type="email" placeholder="Enter your email" disabled />
<FieldDescription>This field is currently disabled.</FieldDescription>
</Field>
)
}
With Error
Enter an invalid email address and press enter to see the error.
import {
Field,
FieldControl,
FieldError,
FieldLabel,
} from "@/components/ui/field"
export function FieldWithErrorDemo() {
return (
<Field>
<FieldLabel>Email</FieldLabel>
<FieldControl type="email" placeholder="Enter your email" />
<FieldError>Please enter a valid email address.</FieldError>
</Field>
)
}
With Validity
{ "state": { "badInput": false, "customError": false, "patternMismatch": false, "rangeOverflow": false, "rangeUnderflow": false, "stepMismatch": false, "tooLong": false, "tooShort": false, "typeMismatch": false, "valid": null, "valueMissing": false }, "error": "", "errors": [], "value": null, "initialValue": null, "validity": { "badInput": false, "customError": false, "patternMismatch": false, "rangeOverflow": false, "rangeUnderflow": false, "stepMismatch": false, "tooLong": false, "tooShort": false, "typeMismatch": false, "valid": null, "valueMissing": false } }
"use client"
import {
Field,
FieldControl,
FieldLabel,
FieldValidity,
} from "@/components/ui/field"
export function FieldWithValidityDemo() {
return (
<Field>
<FieldLabel>Email</FieldLabel>
<FieldControl type="email" placeholder="Enter your email" required />
<FieldValidity>
{(validity) => (
<div className="flex w-full flex-col gap-2">
{validity.error && (
<p className="text-xs text-destructive-foreground">
{validity.error}
</p>
)}
<div className="w-full rounded-md bg-muted p-2">
<pre className="no-scrollbar max-h-60 overflow-y-auto font-mono text-xs">
{JSON.stringify(validity, null, 2)}
</pre>
</div>
</div>
)}
</FieldValidity>
</Field>
)
}
Autocomplete Field
Select a item.
"use client"
import {
Autocomplete,
AutocompleteEmpty,
AutocompleteInput,
AutocompleteItem,
AutocompleteList,
AutocompletePopup,
} from "@/components/ui/autocomplete"
import {
Field,
FieldDescription,
FieldLabel,
} from "@/components/ui/field"
const items = [
{ label: "Apple", value: "apple" },
{ label: "Banana", value: "banana" },
{ label: "Orange", value: "orange" },
{ label: "Grape", value: "grape" },
{ label: "Strawberry", value: "strawberry" },
{ label: "Mango", value: "mango" },
{ label: "Pineapple", value: "pineapple" },
{ label: "Kiwi", value: "kiwi" },
{ label: "Peach", value: "peach" },
{ label: "Pear", value: "pear" },
]
export function FieldAutocompleteDemo() {
return (
<Field>
<FieldLabel>Fruits</FieldLabel>
<Autocomplete items={items}>
<AutocompleteInput
placeholder="Search items…"
aria-label="Search items"
/>
<AutocompletePopup>
<AutocompleteEmpty>No items found.</AutocompleteEmpty>
<AutocompleteList>
{(item) => (
<AutocompleteItem key={item.value} value={item}>
{item.label}
</AutocompleteItem>
)}
</AutocompleteList>
</AutocompletePopup>
</Autocomplete>
<FieldDescription>Select a item.</FieldDescription>
</Field>
)
}
Combobox Field
Select a item.
"use client"
import {
Combobox,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
ComboboxList,
ComboboxPopup,
} from "@/components/ui/combobox"
import {
Field,
FieldDescription,
FieldLabel,
} from "@/components/ui/field"
const items = [
{ value: "apple", label: "Apple" },
{ value: "banana", label: "Banana" },
{ value: "orange", label: "Orange" },
{ value: "grape", label: "Grape" },
{ value: "strawberry", label: "Strawberry" },
{ value: "mango", label: "Mango" },
{ value: "pineapple", label: "Pineapple" },
{ value: "kiwi", label: "Kiwi" },
{ value: "peach", label: "Peach" },
{ value: "pear", label: "Pear" },
]
export function FieldComboboxDemo() {
return (
<Field>
<FieldLabel>Fruits</FieldLabel>
<Combobox items={items}>
<ComboboxInput
placeholder="Select an item..."
aria-label="Select an item"
/>
<ComboboxPopup>
<ComboboxEmpty>No results found.</ComboboxEmpty>
<ComboboxList>
{(item) => (
<ComboboxItem key={item.value} value={item}>
{item.label}
</ComboboxItem>
)}
</ComboboxList>
</ComboboxPopup>
</Combobox>
<FieldDescription>Select a item.</FieldDescription>
</Field>
)
}
Combobox Multiple Field
Apple
Strawberry
Select multiple items.
"use client"
import {
Combobox,
ComboboxChip,
ComboboxChips,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
ComboboxList,
ComboboxPopup,
ComboboxValue,
} from "@/components/ui/combobox"
import {
Field,
FieldDescription,
FieldLabel,
} from "@/components/ui/field"
const items = [
{ label: "Apple", value: "apple" },
{ label: "Banana", value: "banana" },
{ label: "Orange", value: "orange" },
{ label: "Grape", value: "grape" },
{ label: "Strawberry", value: "strawberry" },
{ label: "Mango", value: "mango" },
{ label: "Pineapple", value: "pineapple" },
{ label: "Kiwi", value: "kiwi" },
{ label: "Peach", value: "peach" },
{ label: "Pear", value: "pear" },
]
export function FieldComboboxMultiple() {
return (
<Field>
<FieldLabel>Fruits</FieldLabel>
<Combobox items={items} multiple defaultValue={[items[0], items[4]]}>
<ComboboxChips>
<ComboboxValue>
{(value: { value: string; label: string }[]) => (
<>
{value?.map((item) => (
<ComboboxChip key={item.value} aria-label={item.label}>
{item.label}
</ComboboxChip>
))}
<ComboboxInput
placeholder={value.length > 0 ? undefined : "Select items…"}
aria-label="Select items"
/>
</>
)}
</ComboboxValue>
</ComboboxChips>
<ComboboxPopup>
<ComboboxEmpty>No items found.</ComboboxEmpty>
<ComboboxList>
{(item) => (
<ComboboxItem key={item.value} value={item}>
{item.label}
</ComboboxItem>
)}
</ComboboxList>
</ComboboxPopup>
</Combobox>
<FieldDescription>Select multiple items.</FieldDescription>
</Field>
)
}
Textarea Field
Write a short bio. Maximum 500 characters.
"use client"
import {
Field,
FieldControl,
FieldDescription,
FieldLabel,
} from "@/components/ui/field"
import { Textarea } from "@/components/ui/textarea"
export function FieldTextareaDemo() {
return (
<Field>
<FieldLabel>Bio</FieldLabel>
<FieldControl
render={(props) => (
<Textarea placeholder="Tell us about yourself…" {...props} />
)}
/>
<FieldDescription>
Write a short bio. Maximum 500 characters.
</FieldDescription>
</Field>
)
}
Select Field
Select a country
This is an optional field
import {
Field,
FieldDescription,
FieldLabel,
} from "@/components/ui/field"
import {
Select,
SelectItem,
SelectPopup,
SelectTrigger,
SelectValue,
} from "@/components/ui/select"
const items = [
{ label: "Select a country", value: null },
{ label: "United States", value: "us" },
{ label: "United Kingdom", value: "uk" },
{ label: "Canada", value: "ca" },
{ label: "Australia", value: "au" },
]
export function FieldSelectDemo() {
return (
<Field>
<FieldLabel>Country</FieldLabel>
<Select items={items}>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectPopup>
{items.map(({ label, value }) => (
<SelectItem key={value} value={value}>
{label}
</SelectItem>
))}
</SelectPopup>
</Select>
<FieldDescription>This is an optional field</FieldDescription>
</Field>
)
}
Checkbox Field
import { Checkbox } from "@/components/ui/checkbox"
import { Field, FieldLabel } from "@/components/ui/field"
export function FieldCheckboxDemo() {
return (
<Field>
<FieldLabel>
<Checkbox />
Accept terms and conditions
</FieldLabel>
</Field>
)
}
Checkbox Group Field
"use client"
import { Checkbox } from "@/components/ui/checkbox"
import { CheckboxGroup } from "@/components/ui/checkbox-group"
import {
Field,
FieldDescription,
FieldLabel,
} from "@/components/ui/field"
import { Fieldset, FieldsetLegend } from "@/components/ui/fieldset"
export function FieldCheckboxGroupDemo() {
return (
<Field
name="frameworks"
className="gap-4"
render={(props) => <Fieldset {...props} />}
>
<FieldsetLegend className="text-sm font-medium">
Frameworks
</FieldsetLegend>
<CheckboxGroup defaultValue={["react"]}>
<FieldLabel>
<Checkbox value="react" /> React
</FieldLabel>
<FieldLabel>
<Checkbox value="vue" /> Vue
</FieldLabel>
<FieldLabel>
<Checkbox value="svelte" /> Svelte
</FieldLabel>
</CheckboxGroup>
<FieldDescription>Select one or more frameworks.</FieldDescription>
</Field>
)
}
Radio Group Field
"use client"
import {
Field,
FieldDescription,
FieldLabel,
} from "@/components/ui/field"
import { Fieldset, FieldsetLegend } from "@/components/ui/fieldset"
import { Radio, RadioGroup } from "@/components/ui/radio-group"
export function FieldRadioDemo() {
return (
<Field
name="plan"
className="gap-4"
render={(props) => <Fieldset {...props} />}
>
<FieldsetLegend className="text-sm font-medium">
Choose Plan
</FieldsetLegend>
<RadioGroup defaultValue="free">
<FieldLabel>
<Radio value="free" /> Free
</FieldLabel>
<FieldLabel>
<Radio value="pro" /> Pro
</FieldLabel>
<FieldLabel>
<Radio value="enterprise" /> Enterprise
</FieldLabel>
</RadioGroup>
<FieldDescription>Select the plan that fits your needs.</FieldDescription>
</Field>
)
}
Switch Field
import { Field, FieldLabel } from "@/components/ui/field"
import { Switch } from "@/components/ui/switch"
export function FieldSwitchDemo() {
return (
<Field>
<FieldLabel>
<Switch />
Email notifications
</FieldLabel>
</Field>
)
}
Slider Field
This is an optional field
import {
Field,
FieldDescription,
FieldLabel,
} from "@/components/ui/field"
import { Slider } from "@/components/ui/slider"
export function FieldSelectDemo() {
return (
<Field className="items-stretch gap-3">
<FieldLabel>Country</FieldLabel>
<Slider defaultValue={50} />
<FieldDescription>This is an optional field</FieldDescription>
</Field>
)
}
Number Field
Choose a value between 1 and 100.
import { Field, FieldDescription } from "@/components/ui/field"
import {
NumberField,
NumberFieldDecrement,
NumberFieldGroup,
NumberFieldIncrement,
NumberFieldInput,
NumberFieldScrubArea,
} from "@/components/ui/number-field"
export function FieldNumberFieldDemo() {
return (
<Field>
<NumberField defaultValue={1} min={1} max={100}>
<NumberFieldScrubArea label="Quantity" />
<NumberFieldGroup>
<NumberFieldDecrement />
<NumberFieldInput />
<NumberFieldIncrement />
</NumberFieldGroup>
</NumberField>
<FieldDescription>Choose a value between 1 and 100.</FieldDescription>
</Field>
)
}
Complete Form Example
"use client"
import * as React from "react"
import { Button } from "@/components/ui/button"
import { Checkbox } from "@/components/ui/checkbox"
import {
Field,
FieldControl,
FieldDescription,
FieldError,
FieldLabel,
} from "@/components/ui/field"
import { Form } from "@/components/ui/form"
import {
Select,
SelectItem,
SelectPopup,
SelectTrigger,
SelectValue,
} from "@/components/ui/select"
export function FieldCompleteFormDemo() {
const [loading, setLoading] = React.useState(false)
const onSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault()
const formData = new FormData(e.currentTarget)
setLoading(true)
await new Promise((r) => setTimeout(r, 800))
setLoading(false)
const data = {
fullName: formData.get("fullName"),
email: formData.get("email"),
role: formData.get("role"),
newsletter: formData.get("newsletter"),
}
alert(
`Full name: ${data.fullName || ""}\nEmail: ${data.email || ""}\nRole: ${
data.role || ""
}\nNewsletter: ${data.newsletter}`
)
}
return (
<Form onSubmit={onSubmit}>
<Field>
<FieldLabel>
Full Name <span className="text-destructive">*</span>
</FieldLabel>
<FieldControl
name="fullName"
type="text"
placeholder="John Doe"
disabled={loading}
required
/>
<FieldError>Please enter a valid name.</FieldError>
</Field>
<Field>
<FieldLabel>
Email <span className="text-destructive">*</span>
</FieldLabel>
<FieldControl
name="email"
type="email"
placeholder="[email protected]"
disabled={loading}
required
/>
<FieldError>Please enter a valid email.</FieldError>
</Field>
<Field>
<FieldLabel>Role</FieldLabel>
<Select
name="role"
items={[
{ label: "Select your role", value: null },
{ label: "Developer", value: "developer" },
{ label: "Designer", value: "designer" },
{ label: "Product Manager", value: "manager" },
{ label: "Other", value: "other" },
]}
disabled={loading}
>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectPopup>
<SelectItem value="developer">Developer</SelectItem>
<SelectItem value="designer">Designer</SelectItem>
<SelectItem value="manager">Product Manager</SelectItem>
<SelectItem value="other">Other</SelectItem>
</SelectPopup>
</Select>
<FieldDescription>This is an optional field</FieldDescription>
</Field>
<Field>
<div className="flex items-center gap-2">
<Checkbox name="newsletter" disabled={loading} />
<FieldLabel className="cursor-pointer">
Subscribe to newsletter
</FieldLabel>
</div>
</Field>
<Button type="submit" disabled={loading}>
Submit
</Button>
</Form>
)
}