Field
@sushindustries/uiA labelled control with one line under it - the error is announced by being pointed at, not by being red.
Examples are the tab where the component is shown doing a job, not demonstrating a prop. The API tab already lists the props.
tanstacktanstack add https://adamjurek.com/r/tanstack/field.jsonpnpm dlx shadcn@latest add https://adamjurek.com/r/shadcn/field.jsonPress Compare. The frames are real viewports, so a layout that breaks at 320 breaks here too rather than in somebody's hands.
In a page
import { useState } from "react";
import { Button, Field, Input } from "@sushindustries/ui";
export function NewsletterForm() {
const [email, setEmail] = useState("");
const [error, setError] = useState<string>();
return (
<form
className="flex col gap-4"
onSubmit={(e) => {
e.preventDefault();
if (!email.includes("@")) {
setError("That does not look like an email.");
return;
}
setError(undefined);
}}
>
<Field label="Email" hint="Once a month, at most." error={error}>
<Input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
</Field>
<Button type="submit">Subscribe</Button>
</form>
);
}tsx
What this example is not
Not the validation. FieldFieldA labelled control with one line under it - the error is announced by being pointed at, not by being red.@sushindustries/ui · content only ever displays whatever string it is handed
as error - deciding when that string exists, and what it says, is the
form's job entirely.