Krizaka
Documentation

Form

A form = a schema (zod 4) + the package's fields, on TanStack Form v1: each error shows once the field is left and goes as soon as it is fixed, in the person's language (i18n keys, never the engine's English), a value can be checked on the server as it is typed, and the server's refusals land under their fields — web and React Native, the same schema.

Web + MobileBêtaFormulaires

Web et mobile — le même composant pour React et React Native. Bêta : son API peut encore changer à une version mineure.

Quand l’utiliser

  • Any form that sends something: sign-up, profile, upload details, an amount, an audience, a report, settings.
  • When the server must re-check the same rules: the schema is shared (a product keeps it in packages/core) and @krizaka/ui/form/server parses with it in a Server Action.
  • When a value depends on the server (a username's availability): validateAsync on the field, debounced and aborted.

Quand ne pas l’utiliser

  • For a single search box that filters as you type: no submit, no validation.À la place : Search field
  • For a filter bar over a list: its state is the address, not a form.À la place : Filter bar
  • For a setting that applies at once on its own (a theme switch): the control alone.À la place : Switch

Installation

Installer

npm install @krizaka/ui @krizaka/tailwind @krizaka/tokens tailwindcss

Styles

@import "tailwindcss";
@import "@krizaka/tailwind";
@import "@krizaka/ui/tailwind.css";

Importer

import { createKrizakaForm, useFormWithAction, latestBirthDate, useKrizakaField, formMessage } from "@krizaka/ui/form";

Exemples

Sign-up

Orochia's sign-up: a username checked as it is typed with a free one offered, an 18+ date of birth typed as day · month · year, a server refusal on its field.

We send a link to confirm it.

@

At least 8 characters.

Date of birth

Private, never shown.

Profile

Saved by a mutation of @krizaka/query: categories, tags, a list of links that grows (form.FieldArray).

Up to 160 characters.

Travel

Up to three.

astromountains
Links

Upload

A video and what describes it — the file, a title, a description, tags, who can watch — sent together.

Video

Drop your video here

MP4 or MOV, up to 4 GB.

Up to 10, separated by commas.

Amount

A tip stored in cents (Money), typed the locale's way; presets set the field from outside.

Between $1 and $500.

Audience

Cards to choose who watches, the price only for subscribers (form.Watch), a publication date.

Who can watch

Empty: at once.

Viewers can comment under the video.

Settings

Sent by a Server Action (useFormWithAction): switches, a menu, a slider, a choice.

What happened on your channel.

Autoplay volume
Video quality

Report

One reason among a few, details, and blocking the account in the same step.

What is wrong?

Optional. What should our team look at?

Props

Checkbox

A box of the form (boolean): terms to accept, an option.

PropTypeDéfautDescription
labelrequisReactNode—The words next to the box, clickable with it — text, or a sentence with links (terms, privacy).
namerequisstring—The field's name in the schema: email, address.city, links[0].url (typed by the form).
classNamestring—Classes merged on the field's root.
disabledboolean—Not available.
hintstring—A help text under the control, read with it; the error takes its place when there is one.

Combobox

A choice among many, typed to filter or fetched: one value (string) or several (string[]).

PropTypeDéfautDescription
labelrequisstring—The visible label, passed translated (also the control's accessible name).
namerequisstring—The field's name in the schema: email, address.city, links[0].url (typed by the form).
classNamestring—Classes merged on the field's root.
creatableboolean—Offers to create the query as a value.
disabledboolean—Not available.
hintstring—A help text under the control, read with it; the error takes its place when there is one.
labelsPartial<ComboboxLabels>—The words of the control, passed translated.
multipleboolean—Several values (string[]), shown as chips; one (string) by default.
onSearch((query: string, signal: AbortSignal) => Promise<readonly ComboboxOption[]>)—Fetches the options for a query (debounced, aborted by a newer one).
optionsreadonly ComboboxOption[][]The options, filtered as the person types.
placeholderstring—The input's placeholder, passed translated.

DateField

A date of the form (YYYY-MM-DD, "" for none): a calendar, or day · month · year typed in the locale's order.

PropTypeDéfautDescription
labelrequisstring—The visible label, passed translated (also the control's accessible name).
namerequisstring—The field's name in the schema: email, address.city, links[0].url (typed by the form).
autoComplete"off" | "bday"—bday for a date of birth.
classNamestring—Classes merged on the field's root.
disabledboolean—Not available.
entry"calendar" | "parts"calendarcalendar (default: a date near today — a publication, an appointment) or parts (day · month · year typed: a memorable date, a birth date).
hintstring—A help text under the control, read with it; the error takes its place when there is one.
labels(Partial<DatePickerLabels> & Partial<Record<DatePart, string>>)—The words of the calendar, or the names of the boxes (day, month, year), passed translated.
maxstring—The latest date (ISO), for the calendar (latestBirthDate(18) for an age gate).
minstring—The earliest date (ISO), for the calendar.

FieldArray

A list of fields that grows and shrinks (links, tiers, guests): each item's fields named links[0].url.

PropTypeDéfautDescription
childrenrequis(array: KrizakaFieldArray<unknown>) => ReactNode—Draws the items: items, push, remove, move, fieldName(i, "url") for the fields of an item.
namerequisstring—The array's name in the schema (typed by the form).

FileUpload

Files of the form (File[]): a drop zone, then the chosen files, each removable.

PropTypeDéfautDescription
browseLabelrequisstring—The button that opens the file picker, passed translated.
labelrequisstring—The visible label, passed translated (also the control's accessible name).
namerequisstring—The field's name in the schema: email, address.city, links[0].url (typed by the form).
removeLabelrequis(fileName: string) => string—The name of a file's remove button ((name) => "Remove " + name), passed translated.
titlerequisstring—The title in the zone ("Drop your video here"), passed translated.
acceptstring—The types accepted (video/*, image/png,.pdf).
classNamestring—Classes merged on the field's root.
disabledboolean—Not available.
hintstring—What is accepted, in words ("MP4 or MOV, up to 4 GB").
maxFilesnumber—The most files.
maxSizenumber—The largest file, in bytes.
multipleboolean—Several files (File[], up to maxFiles); one by default (still a File[] of one).
refusalLabel((rejection: FileRejection) => string)—The words of a refused file ((r) => r.file.name + " is too large").

FormError

The whole form's error — a refusal of the server that belongs to no field (a conflict, too many tries, no network).

PropTypeDéfautDescription
classNamestring—Classes merged on the alert.
titlestring—A headline above the message ("We could not create your account"), passed translated.

FormField

A field drawn by the app (a control the package does not have): the form's value, errors and ids, any markup.

PropTypeDéfautDescription
childrenrequis(field: KrizakaField<unknown>) => ReactNode—Draws the field: its value, setter, error and ids (useKrizakaField).
namerequisstring—The field's name in the schema (typed by the form).
asyncDebounceMsnumber—The wait, in ms, before validateAsync.
validateAsyncFieldCheck<unknown>—Checks the value on the server as it changes.

Money

An amount of the form, stored as integer minor units (cents: 1250 = 12.50), typed the locale's way.

PropTypeDéfautDescription
currencyrequisstring—The currency (ISO 4217: USD, EUR, JPY): its sign before the amount, its decimals.
labelrequisstring—The visible label, passed translated (also the control's accessible name).
namerequisstring—The field's name in the schema: email, address.city, links[0].url (typed by the form).
classNamestring—Classes merged on the field's root.
disabledboolean—Not available.
hintstring—A help text under the control, read with it; the error takes its place when there is one.
placeholderstring—An example of an amount, passed translated.

RadioGroup

One choice among a few, all visible.

PropTypeDéfautDescription
labelrequisstring—The visible label, passed translated (also the control's accessible name).
namerequisstring—The field's name in the schema: email, address.city, links[0].url (typed by the form).
optionsrequisreadonly FormOption[]—The choices, all visible (two to five).
classNamestring—Classes merged on the field's root.
disabledboolean—Not available.
hintstring—A help text under the control, read with it; the error takes its place when there is one.
orientation"horizontal" | "vertical"verticalvertical (default) or horizontal.
variant"list" | "cards"listlist (a dot and its words, default) or cards (a whole card is the radio: an amount, a plan, an audience).

Select

One choice among many, in the platform's menu (<select>: accessible and right on phones).

PropTypeDéfautDescription
labelrequisstring—The visible label, passed translated (also the control's accessible name).
namerequisstring—The field's name in the schema: email, address.city, links[0].url (typed by the form).
optionsrequisreadonly FormOption[]—The choices, in the platform's own menu (a country, a category).
classNamestring—Classes merged on the field's root.
disabledboolean—Not available.
hintstring—A help text under the control, read with it; the error takes its place when there is one.
placeholderstring—The first line while nothing is chosen ("Choose a category"), passed translated.

Slider

A number (or a range) of the form, chosen by feel: a share, a volume, a price range.

PropTypeDéfautDescription
labelrequisstring—The visible label, passed translated (also the control's accessible name).
namerequisstring—The field's name in the schema: email, address.city, links[0].url (typed by the form).
classNamestring—Classes merged on the field's root.
disabledboolean—Not available.
formatValue((value: number) => string)—The value as words ("15 %", "3 min"), shown and read.
hintstring—A help text under the control, read with it; the error takes its place when there is one.
maxnumber—The highest value. Default 100.
minnumber—The lowest value. Default 0.
stepnumber—The step. Default 1.
thumbLabels[string, string]—For a range ([number, number]): each thumb's name, passed translated.

Submit

The submit button: busy while the form is sent (not pressable twice), never disabled for an invalid form.

PropTypeDéfautDescription
announcestring—A message announced politely by assistive technology when it changes (“Saved”, “Upload failed”) — passed translated.
asChildboolean—Renders the child (e.g. a <Link>) instead of the <button>, with props, classes and ref merged.
indicatorbooleantrueShows the glyph while loading / with a status. false: you draw your own.
magneticboolean—The button leans a few pixels toward a fine pointer (driven by MotionObserver; never under reduced motion or on touch).
progressnumber | null—Between 0 and 1, while loading: the glyph's trace and a light fill across the button grow to the value (an upload, an export).
shape"rounded" | "pill" | "cut"roundedrounded · pill · cut (45° corners, the Krizaka chamfer).
shimmerboolean—A sheen of light crosses the button on hover — for the one action a page is about.
size"icon" | "sm" | "md" | "lg"mdsm · md · lg, or icon (a square).
status"success" | "error" | null—How the action ended: success draws a check, error a cross (and the button shakes its head once); a ring of the status colour opens around it. Clear it to return to rest.
variant"danger" | "primary" | "gradient" | "secondary" | "outline" | "ghost"primaryThe look: primary (the accent), gradient (accent → accent-2), secondary (a raised surface), outline, ghost, danger.

Switch

An on/off setting of the form (boolean): the label and its hint beside the switch.

PropTypeDéfautDescription
labelrequisstring—The visible label, passed translated (also the control's accessible name).
namerequisstring—The field's name in the schema: email, address.city, links[0].url (typed by the form).
classNamestring—Classes merged on the field's root.
disabledboolean—Not available.
hintstring—A help text under the control, read with it; the error takes its place when there is one.

TagInput

Free words of the form as chips (string[]): tags, keywords.

PropTypeDéfautDescription
labelrequisstring—The visible label, passed translated (also the control's accessible name).
namerequisstring—The field's name in the schema: email, address.city, links[0].url (typed by the form).
classNamestring—Classes merged on the field's root.
disabledboolean—Not available.
hintstring—A help text under the control, read with it; the error takes its place when there is one.
labelsPartial<Pick<ComboboxLabels, "results" | "toggle" | "remove" | "empty" | "create">>—The words of the field, passed translated; English by default.
maxnumber—Most tags; the field stops offering more past it.
normalize((tag: string) => string)—Cleans a word before it is added ((t) => t.toLowerCase().replace(/^#/, "")). An empty result is ignored.
placeholderstring—The input's placeholder, passed translated.
separatorsreadonly string[]—Keys that add the word, besides Enter. Default [","].
suggestionsreadonly string[]—Words offered as the person types (their own history, a curated list).

TextArea

A longer text of the form (a bio, a description, a report).

PropTypeDéfautDescription
labelrequisstring—The visible label, passed translated (also the control's accessible name).
namerequisstring—The field's name in the schema: email, address.city, links[0].url (typed by the form).
classNamestring—Classes merged on the field's root.
disabledboolean—Not available.
hintstring—A help text under the control, read with it; the error takes its place when there is one.
maxLengthnumber—The most characters.
placeholderstring—An example of a value, passed translated.
rowsnumber4The visible lines. Default 4.

TextField

A text field of the form: label, input, hint or error, an optional check on the server.

PropTypeDéfautDescription
labelrequisstring—The visible label, passed translated (also the control's accessible name).
namerequisstring—The field's name in the schema: email, address.city, links[0].url (typed by the form).
asyncDebounceMsnumber—The wait, in ms, between the last key and validateAsync. Default 350.
autoCompletestring—The browser's autofill (email, username, new-password, name).
availableHintstring—The words once validateAsync accepted the value ("@eric is free"), passed translated.
checkingLabelstringCheckingThe name of the wait while it checks ("Checking"), passed translated.
classNamestring—Classes merged on the field's root.
disabledboolean—Not available.
hintstring—A help text under the control, read with it; the error takes its place when there is one.
inputMode"none" | "search" | "text" | "tel" | "url" | "email" | "numeric" | "decimal"—The keyboard on a phone (numeric, decimal).
maxLengthnumber—The most characters.
placeholderstring—An example of a value, passed translated — never the label.
startReactNode—Something before the text (an @, an icon).
transform((raw: string) => string)—Cleans what is typed before it is stored ((v) => v.toLowerCase().replace(/\s+/g, "_")).
type"search" | "text" | "tel" | "url" | "email" | "password"texttext (default), email, password, url, tel, search: the right keyboard on a phone.
validateAsyncFieldCheck<string>—Checks the value on the server as it is typed (availability): an error key, or nothing when it is fine.

Watch

Renders from a field's current value (a part shown only when a box is ticked, a total).

PropTypeDéfautDescription
childrenrequis(value: unknown) => ReactNode—Draws from its current value: show a part of the form only when a box is ticked.
namerequisstring—The field to follow (typed by the form).

Accessibilité

  • Every control is named by its visible label; its hint and its error are in aria-describedby, and an invalid control has aria-invalid.
  • Errors are announced (role="alert"); a refused submit focuses the first invalid field on the web and announces the first error on native.
  • An availability check names its wait (checkingLabel) and says when the value is free (availableHint): never by colour alone.
  • A date of birth is three labelled boxes in the locale's order with numeric keypads and bday autofill, not a calendar to scroll through decades.

Clavier

TouchesAction
EnterSends the form from a text field (web); the keyboard's return key moves to the next field (native).
TabLeaves a field: from then on its error shows, and goes as soon as it is fixed.

Bonnes pratiques

  • Define the form once (createKrizakaForm({ schema, defaultValues })) beside the API's contract; use it in components with form.useForm({ onSubmit }).
  • Name refusals with keys in the schema (z.string().regex(re, "signUp.username.format")) and give the words in messages/*.json; the generic ones are form.errors.* (required, tooShort {minimum}…).
  • Send with a mutation of @krizaka/query (onSubmit: (v) => mutation.mutateAsync(v)) or a Server Action (useFormWithAction): a thrown KrizakaApiError or { ok: false, problem } puts its fields under their fields.
  • Never disable the submit button for an invalid form: a refused submit shows every error and focuses the first.
  • Pick the field for the value: DateField entry="parts" for a memorable date (a birth date), the calendar for a date near today; Money stores cents; RadioGroup for two to five visible choices, Select beyond.
  • Need a control the package does not have? form.Field gives its value, setter, error and ids — never import @tanstack/* in a product.

Générée depuis le code de @krizaka/ui 3.1.0 : son meta.ts, ses exemples et ses types.Modifier cette documentation sur GitHub

Sur cette page