Fields
The fields where the person types or picks something. They are as tall as a button: a field and a button placed side by side line up.
TextField
A one-line text field, pill-shaped, with an icon at the start. It has no visible title: its aria-label names it for screen readers.
A refused field takes aria-invalid: its border, background and text turn to the danger colours. The reason goes right under it, in a StatusLine with tone="error", lined up with the field's icon.
import { TextField } from 'hodi:sdk'
import { Mail } from 'lucide-react'
<TextField
icon={Mail}
aria-label="E-mail"
placeholder="you@example.com"
value={email}
onChange={e => setEmail(e.target.value)}
/>iconLucideIconThe icon at the start of the field, a Lucide icon.
aria-labelstringThe field's name, for screen readers.
onClear?() => voidFor a search: a round cross shows as soon as the field holds text, and a click on it calls this function.
aria-invalid?booleanPuts the field in the danger colours, when what was typed was refused.
…InputHTMLAttributesEverything an <input> accepts: value, onChange, type, placeholder…
PasswordField
A password field, with an eye to show what is typed. For a new password, PasswordRing replaces the padlock and shows its strength, and PasswordGauge goes under the field.
Weak · This password is too common: pick another.
import { PasswordField, PasswordGauge, PasswordRing } from 'hodi:sdk'
<PasswordField
aria-label="Password"
value={password}
onChange={e => setPassword(e.target.value)}
lead={<PasswordRing password={password} />}
/>
<PasswordGauge password={password} />aria-labelstringThe field's name, for screen readers.
icon?LucideIconThe icon at the start of the field. It is a padlock by default.
invalid?booleanPuts the field in the danger colours, when the password was refused. The reason goes under it, in a StatusLine, in place of PasswordGauge.
lead?ReactNodeAn element in place of the icon, such as a PasswordRing.
…InputHTMLAttributesEverything an <input> accepts, except type.
PasswordGauge
The line under a new password. It says its strength and what would make it stronger, and goes away as soon as it is strong enough. PasswordRing takes the same prop.
passwordstringThe password typed, whose strength the line measures.
PinField
A code field, with one box per character. As soon as the last character is typed, the code checks itself, without a button.
import { PinField } from 'hodi:sdk'
<PinField
label="Code"
length={6}
value={code}
onChange={setCode}
onComplete={check}
align="start"
/>labelstringThe field's name, for screen readers.
lengthnumberThe number of characters in the code: 8 for the codes of I have a code, 6 for an authenticator app.
valuestringWhat is typed so far.
onChange(value: string) => voidCalled at each character typed or erased.
onComplete?(value: string) => voidCalled when the whole code is typed, to check it.
state?'idle' | 'wrong' | 'right'wrong turns the boxes red, right turns them green.
align?'center' | 'start'start lines the boxes up on the left, in a form. center centres them, when the code has its own screen.
masked?booleanShows dots instead of the characters.
characters?RegExpThe characters accepted. Only digits by default.
disabled?booleanThe field is greyed out and can't be filled in.
autoFocus?booleanPuts the cursor in the first box as soon as it shows.
Toggle
The switch, for a setting that turns on or off. In a settings page, it goes at the end of a SettingRow.
import { Toggle } from 'hodi:sdk'
<Toggle
checked={morning}
label="Say hello in the morning"
onChange={setMorning}
/>checkedbooleantrue when the switch is on.
labelstringWhat the switch turns on, for screen readers.
onChange(checked: boolean) => voidCalled at each switch, with the new state.
disabled?booleanThe switch is greyed out and doesn't switch.
Checkbox
A checkbox followed by a sentence, for an agreement, such as accepting terms.
import { Checkbox } from 'hodi:sdk'
<Checkbox checked={keep} onChange={setKeep}>Keep my greetings</Checkbox>checkedbooleantrue when the box is ticked.
onChange(checked: boolean) => voidCalled at each click, with the new state.
childrenReactNodeThe sentence next to the box.
disabled?booleanThe box is greyed out and can't be ticked.
AgeCheckbox
The I am at least 13 years old box, followed by the text each plugin adds with ageConsent. Every form that creates an account has this box.
import { AgeCheckbox } from 'hodi:sdk'
<AgeCheckbox checked={adult} onChange={setAdult} />checkedbooleantrue when the box is ticked.
onChange(checked: boolean) => voidCalled at each click, with the new state.
Segmented
A choice between a few options, in a pill, such as Light · Dark · System. In a settings page, it is passed to a SettingRow's choice prop.
import { Segmented } from 'hodi:sdk'
<Segmented
label="Moment"
value={moment}
options={[
{ value: 'morning', label: 'Morning' },
{ value: 'noon', label: 'Noon' },
{ value: 'evening', label: 'Evening' }
]}
onChange={setMoment}
/>labelstringThe choice's name, for screen readers.
valuestring | numberThe value of the chosen option.
options{ value; label; title? }[]The options, in order. Each has a value and a text; its title shows on hover.
onChange(value) => voidCalled when the person picks an option, with its value.
wide?booleanThe choice takes the whole width, shared equally between the options.