Simple Form
Fill this in and submit — it calls the registry-backed users.create handler below and shows the inline success feedback, exactly as described in the schema.
This tutorial renders a form with validation, options, and a registry-backed submit handler.
Use this when you want a focused form preview without a table.
Why FluiKitForm directly
The page file below renders FluiKitForm directly instead of <FluiKit>. This is deliberate: <FluiKit> only opens a form.mode: "page" surface from a Create trigger button (its stand-in for the table toolbar when table.enabled is false), so the form is hidden behind an extra click. That fits a resource page where creating is one of several actions, but not a dedicated route like app/users/new/page.tsx, where the form should already be visible the moment the user lands there. Use FluiKitForm directly (see Direct Usage) whenever a route's entire purpose is showing one form.
File structure
app/
users/
new/
page.tsx
schemas/
users/
user.form.schema.ts
lib/
vibeflui/
registry.tsxSchema file
schemas/users/user.form.schema.ts
export const userFormSchema = {
resource: "users",
title: "Create user",
identity: {
key: "id",
param: "id"
},
table: {
enabled: false
},
form: {
mode: "page",
fields: [
{ name: "name", label: "Name", required: true, minLength: 2 },
{ name: "email", label: "Email", type: "email", required: true },
{
name: "role",
label: "Role",
type: "select",
required: true,
options: [
{ label: "Admin", value: "admin" },
{ label: "Editor", value: "editor" },
{ label: "Viewer", value: "viewer" }
]
},
{ name: "active", label: "Active", type: "switch", defaultValue: true }
]
},
actions: {
create: {
enabled: true,
label: "Save user",
handler: "users.create"
}
},
registry: {
actionHandlers: ["users.create"]
},
feedback: {
mode: "inline"
}
} as const;The schema references users.create by string. The actual function lives in the registry.
Registry file
lib/vibeflui/registry.tsx
import { createRegistry } from "@vibeflui/core";
export const vibefluiRegistry = createRegistry({
actionHandlers: {
"users.create": async ({ values }) => ({
status: true,
code: 200,
message: `${String(values?.name ?? "User")} created successfully`,
data: values
})
}
});Page file
app/users/new/page.tsx
"use client";
import { useState } from "react";
import {
FluiKitFeedback,
FluiKitForm,
FluiKitProvider,
executeOperation,
normalizeSchema,
type FluiKitFeedbackMessage
} from "@vibeflui/core";
import { userFormSchema } from "@/schemas/users/user.form.schema";
import { vibefluiRegistry } from "@/lib/vibeflui/registry";
const schema = normalizeSchema(userFormSchema);
export default function NewUserPage() {
const [feedback, setFeedback] = useState<FluiKitFeedbackMessage | null>(null);
const handleSubmitUser = async (values: Record<string, unknown>) => {
const result = await executeOperation({
schema,
operation: "create",
values,
registry: vibefluiRegistry
});
setFeedback({
status: "success",
title: "Saved",
message: String((result.data as { message?: unknown } | undefined)?.message ?? "User saved")
});
};
return (
<FluiKitProvider registry={vibefluiRegistry}>
<FluiKitFeedback
schema={schema}
mode="inline"
feedback={feedback}
onClose={() => setFeedback(null)}
/>
<FluiKitForm
schema={schema}
mode="create"
onSubmit={handleSubmitUser}
/>
</FluiKitProvider>
);
}Expected submit response
{
"status": true,
"code": 200,
"message": "Ada Lovelace created successfully"
}