Input
useInput(options) returns { root, input }: a .field wrapper with the label and message already wired through for, aria-invalid and aria-describedby. inputClass(options) returns the control classes for SSR markup.
Basic field
import { useInput } from "@katanakit/ui";
const { root } = useInput({
label: "Email",
type: "email",
name: "email",
placeholder: "you@example.com",
help: "We only use it for receipts.",
});
form.append(root);Error state
useInput({ label: "Email", type: "email", error: "Enter a valid email." });Contract
Every component in the kit follows one shape. Pure builders return a class string and touch nothing; factories build a DOM element and need a browser.
| Surface | Import | Needs a DOM |
|---|---|---|
| Pure class builder | inputClass | No — safe during SSR |
| Element factory | useInput | Yes — throws with a pointer to the pure surface |
// Server and templates — pure
<div class={ inputClass({ /* … */ }) }></div>
// Browser — imperative
document.body.append(useInput({ /* … */ }));Class names are unprefixed. The root class is field, not kk-field, and every component rule is wrapped in @layer katana.
That matters because these names collide 1:1 with daisyUI. Unlayered CSS always beats layered CSS regardless of specificity or import order, so loading both is deterministic instead of "whoever came last". See why.
Options
| Option | Type | Default | Notes |
|---|---|---|---|
label | string | — | Rendered as <label for>. |
name | string | — | name attribute; derives the input id. |
type | "text" | "email" | "password" | "search" | "tel" | "url" | "text" | Native input type. |
value | string | — | Initial value. |
placeholder | string | — | Placeholder text. |
help | string | — | Helper text (aria-describedby). |
error | string | — | Error message; adds aria-invalid + styling. |
required | boolean | false | Native required + visual marker. |
disabled | boolean | false | Native disabled state. |
onInput | (value: string) => void | — | Fired on every input event. |
Validation
Pair the field with useValidate() from katanakit-js: run the Safe Result and pass error.issues[0].message to useInput — or rebuild the field when the state changes.