Primitives
Input
A field for one line of text.
The name shows in the list of projects.
import { Field, Input } from 'ferry-ui'
export default function InputHero() {
return (
<Field label="Project name" hint="The name shows in the list of projects." className="w-full max-w-sm">
<Input placeholder="Billing portal" />
</Field>
)
}aria-label.SearchInput of List Toolbar.Import the component. An input has one part.
import { Input } from 'ferry-ui'
<Input />Give the same value to the htmlFor of the Label and to the id of the input.
Field adds the label, the hint and the error message for you.
import { Input, Label } from 'ferry-ui'
export default function InputLabel() {
return (
<div className="flex w-full max-w-sm flex-col gap-2">
<Label htmlFor="billing-email">Billing email</Label>
<Input id="billing-email" type="email" placeholder="maya@example.com" />
</div>
)
}The size prop sets the height. The default is md.
import { Input } from 'ferry-ui'
export default function InputSizes() {
return (
<div className="flex w-full max-w-sm flex-col gap-3">
<Input size="tiny" placeholder="Tiny, 26px" aria-label="Tiny input" />
<Input size="sm" placeholder="Small, 30px" aria-label="Small input" />
<Input size="md" placeholder="Medium, 34px" aria-label="Medium input" />
<Input size="lg" placeholder="Large, 38px" aria-label="Large input" />
</div>
)
}| Size | Height | Use |
|---|---|---|
tiny | 26px | Toolbars and table cells. |
sm | 30px | Filters and dense forms. |
md | 34px | Form fields. |
lg | 38px | Sign-in forms. |
The heights are the same as the heights of Button. Give the same size to the input and to the button.
The default size of a button is sm. The default size of an input is md.
import { Button, Input } from 'ferry-ui'
export default function InputWithButton() {
return (
<div className="flex w-full max-w-sm gap-2">
<Input size="sm" type="email" placeholder="maya@example.com" aria-label="Email of the new member" />
<Button size="sm" variant="primary">
Invite
</Button>
</div>
)
}Set mono for a value that a program reads: an identifier, a slug, a URL or a key.
The app sends each event to this address.
import { Field, Input } from 'ferry-ui'
export default function InputMono() {
return (
<Field label="Webhook URL" hint="The app sends each event to this address." className="w-full max-w-sm">
<Input mono type="url" placeholder="https://example.com/webhooks" />
</Field>
)
}disabled makes the input unavailable. readOnly shows a value that the user can copy but not change.
aria-invalid shows the error border. Field sets it when you pass error.
Only an owner can change the name.
Enter a valid email address.
import { Field, Input } from 'ferry-ui'
export default function InputStates() {
return (
<div className="flex w-full max-w-sm flex-col gap-5">
<Field label="Workspace" hint="Only an owner can change the name.">
<Input disabled defaultValue="Acme" />
</Field>
<Field label="Project ID">
<Input readOnly mono defaultValue="prj_8f2k1m9x" />
</Field>
<Field label="Billing email" error="Enter a valid email address.">
<Input type="email" defaultValue="maya@example" />
</Field>
</div>
)
}An input holds its value by default. Use defaultValue for the first value.
To control the value, pass value and onChange.
Slug: billing-portal
import * as React from 'react'
import { Field, Input } from 'ferry-ui'
export default function InputControlled() {
const [name, setName] = React.useState('Billing portal')
const slug = name
.trim()
.toLowerCase()
.replace(/[^a-z0-9]+/g, '-')
return (
<Field label="Project name" hint={`Slug: ${slug === '' ? 'none' : slug}`} className="w-full max-w-sm">
<Input value={name} onChange={(event) => setName(event.target.value)} />
</Field>
)
}inputVariants returns the classes of Input. Use it for an element that cannot be an <input>.
An element that is not an input gets the read-only background.
import * as React from 'react'
import { Input, Label, inputVariants } from 'ferry-ui'
const SEAT_PRICE = 20
export default function InputVariantsHelper() {
const [seats, setSeats] = React.useState('12')
const total = (Number(seats) || 0) * SEAT_PRICE
return (
<div className="flex w-full max-w-sm flex-col gap-2">
<Label htmlFor="plan-seats">Seats</Label>
<div className="flex gap-2">
<Input
id="plan-seats"
type="number"
size="sm"
min={1}
className="w-24"
value={seats}
onChange={(event) => setSeats(event.target.value)}
/>
<output
htmlFor="plan-seats"
aria-label="Monthly total"
className={inputVariants({ size: 'sm', mono: true, className: 'flex items-center' })}
>
${total}.00 / month
</output>
</div>
</div>
)
}aria-describedby. Field does this for you.Input also accepts each attribute of the <input> element. The numeric size attribute is not available.
| Prop | Type | Default |
|---|---|---|
size | "tiny" | "sm" | "md" | "lg" | md |
Control height, matched to Button sizes so fields and buttons line up in a row: | ||
mono | boolean | false |
Monospace face at 13px. Use for machine values the user types or copies (identifiers, slugs, URLs, keys, hashes); keep prose fields in the sans face. | ||
inputVariants(options) returns a string of classes.
| Option | Type | Role |
|---|---|---|
size | tiny, sm, md or lg | The height. The default is md. |
mono | boolean | The monospace font. The default is false. |
className | string | More classes for the element. |