Skip to Content
GuidesForm Examples

Form Examples

Basic Form

'use client' import { Form, FormInput, FormSelect, FormSection } from '@/components/ui' import { Button } from '@/components/ui' export default function UserForm() { return ( <Form initialValues={{ name: '', email: '', role: 'user' }} onSubmit={(values) => console.log(values)} > <FormSection title="User Information" description="Enter user details"> <FormInput accessor="name" label="Name" required /> <FormInput accessor="email" label="Email" type="email" required /> <FormSelect accessor="role" label="Role" options={[ { label: 'User', value: 'user' }, { label: 'Admin', value: 'admin' }, ]} /> </FormSection> <Button type="submit">Submit</Button> </Form> ) }

Form includes default padding (px-8 pb-8) and spacing (space-y-6).

Resource 2.0 belongsTo Select

When shadpanel resource Post sees author User @relation(fields: [authorId], ...), the create form is equivalent to:

<FormSelect accessor="authorId" label="Author" options={userOptions} />

Load options from the generated server action:

const rows = await getUserOptions() const userOptions = rows.map((u) => ({ label: u.name ?? u.email ?? String(u.id), value: String(u.id), }))

Covered authorId scalars are not rendered as a second input. A lone roleId without a Role relation stays a numeric/string FormInput.

Grid + Validation

<Form initialValues={{ firstName: '', lastName: '', email: '' }} onSubmit={save}> <FormSection title="Profile"> <FormGrid columns={{ sm: 1, md: 2 }} gap={4}> <FormInput accessor="firstName" label="First name" required /> <FormInput accessor="lastName" label="Last name" required /> </FormGrid> <FormInput accessor="email" label="Email" type="email" required validation={{ pattern: { value: /^[^@]+@[^@]+$/, message: 'Enter a valid email', }, }} /> </FormSection> <Button type="submit">Save</Button> </Form>

DateTime and Checkbox (Resource Scalars)

<FormCheckbox accessor="published" label="Published" /> <FormDateTimePicker accessor="publishedAt" label="Published at" />

Next Steps

Last updated on