Field and inline validation
A label, control and one message slot around an input
Installation
npx shadcn@latest add @sudokw/components-fieldimport { Field } from "@gpuixui/components";Usage
import { Effect, Option, Schema } from "effect";
import { useState } from "react";
import { Field, FieldInput } from "@gpuixui/components/field";
import { validate } from "@gpuixui/components/validation/logic";
const WorkspaceSlug = Schema.NonEmptyString.check(
Schema.isPattern(/^[a-z0-9]+(-[a-z0-9]+)*$/, {
identifier: "WorkspaceSlugPattern",
title: "Workspace URL",
message: "Use lowercase letters, numbers and single hyphens",
}),
);
export const WorkspaceForm = () => {
const [slug, setSlug] = useState("");
const [error, setError] = useState<string>();
const submit = () => {
const message = Effect.runSync(validate(WorkspaceSlug)(slug));
setError(Option.getOrUndefined(message));
};
return (
<Field
label="Workspace URL"
description="Lowercase words joined by hyphens."
error={error}
required
>
<FieldInput
value={slug}
onChange={(event) => setSlug(event.value ?? "")}
/>
</Field>
);
};Composition
Field
├── FieldLabel
├── FieldDescription
├── FieldError
└── FieldInput
Fieldset
└── FieldAPI reference
| Part | Prop | Type | Default |
|---|---|---|---|
Field | label | string — the visible label and the input's name | required |
Field | description | string — hidden while error is present | — |
Field | error | string — the message, which also paints the control invalid | — |
Field | required | boolean — appends the * marker | false |
Field | className | string — joined after the recipe | — |
Field | children | the control; only FieldInput is accepted | — |
FieldLabel | required | boolean — the marker without changing the name | false |
FieldDescription | children | ReactNode | — |
FieldError | children | ReactNode | — |
FieldInput | invalid | boolean — overrides the field's own error as the validity signal | the field's state |
FieldInput | disabled | boolean — also inferred from a disabled Fieldset | false |
FieldInput | style | StateStyle<{ disabled, focused, invalid }> | the recipe |
FieldInput | value / defaultValue | string — the text; omit value to let the field keep its draft | — |
FieldInput | onValueChange / onChange | (value: string) => void · the raw host payload, first | — |
FieldInput | onSubmit | (event: EventPayload) => void — Enter in the input | — |
FieldInput | placeholder / readOnly / autoFocus | string · boolean · boolean | — |
FieldInput | size / fullWidth / tabIndex | "sm" | "md" | "lg" · boolean · number | "md" · false · the field's place |
FieldInput | testId | string — a stable locator | — |
FieldInput | ref / aria-id / onLayout | the addressed element: focus it, measure it, name it for automation | — |
FieldInput | onClick / onKeyDown / onKeyUp / onFocus / onBlur | host handlers, composed with the field's own | — |
Fieldset | legend | string — the visible heading and the group's name | required |
Fieldset | disabled | boolean — reaches the controls that honour it | false |
Edit this page on GitHubapps/docs/content/docs/components/field.mdx