FluiKitForm
FluiKitForm renders form fields from a NormalizedFluiKitConfig.
Most pages use it through FluiKit. Direct usage is useful for local demos or custom flows that already normalize the schema.
Props
TS
type FluiKitFormProps = {
schema: NormalizedFluiKitConfig;
mode?: "create" | "edit" | "view";
row?: Record<string, unknown>;
initialValues?: Record<string, unknown>;
className?: string;
onSubmit?: (values, context) => void | Promise<void>;
onCancel?: () => void;
};Default behavior
| Feature | Behavior |
|---|---|
mode | Defaults to create. |
| values | Built from initialValues or mapRowToFormValues(row, schema.form.fields, mode). |
| view mode | Uses edit-style row mapping but renders fields read-only. |
| validation | Runs built-in and registry validation through validateValuesWithRegistry. |
| computed values | Applies applyComputedValues before validation and submit. |
| transformers | Applies transformValuesWithRegistry before onSubmit. |
| submit label | form.submitLabel, otherwise Update in edit mode or Create in create mode. |
| cancel label | form.cancelLabel, otherwise Cancel. |
Layout behavior
FluiKitForm renders fields in this priority:
layout.type: "tabs"withlayout.tabslayout.type: "wizard"withlayout.stepsform.groupsform.sections- all
form.fields
Grouped or sectioned forms still render ungrouped fields after the configured groups or sections.
Wizard behavior
Wizard steps validate only the current step before moving forward. The final step submits the full resolved value object.
schemas/users/users.schema.ts
TS
export const usersSchema = {
version: "1.0.0",
resource: "users",
layout: {
type: "wizard",
steps: [
{ key: "basic", title: "Basic Information", fields: ["name", "email"] },
{ key: "access", title: "Access", fields: ["roleId", "status"] }
]
},
form: {
fields: [
{ name: "name", label: "Name", type: "text", required: true },
{ name: "email", label: "Email", type: "email", required: true },
{
name: "roleId",
label: "Role",
type: "select",
options: [
{ label: "Admin", value: "admin" },
{ label: "Editor", value: "editor" }
]
},
{
name: "status",
label: "Status",
type: "select",
options: [
{ label: "Active", value: "active" },
{ label: "Pending", value: "pending" }
]
}
]
}
} as const;app/users/create-form.tsx
TSX
"use client";
import { FluiKitForm, normalizeSchema } from "@vibeflui/core";
import { usersSchema } from "@/schemas/users/users.schema";
const schema = normalizeSchema(usersSchema);
export function CreateUserForm() {
return (
<FluiKitForm
schema={schema}
mode="create"
onSubmit={async (values) => {
await saveUser(values);
}}
/>
);
}This example does not need a FluiKitProvider or registry because none of its fields reference a component, adapter, or optionLoader.
Theme slots
The form uses these theme slots:
formfieldWrapperlabelinputerroractionButton