Schema-driven registration
One fields array with two titled sections and a two-column grid (it collapses to one column on mobile). Validation runs once a field is touched; the submit button shows a spinner while onSubmit resolves, then the success line appears. Submit it empty to see the error summary and focus jump to the first invalid field.
import { Form } from '@roy-ui/ui';
import type { FormField, FormSection } from '@roy-ui/ui';
const fields: FormField[] = [
{ name: 'email', type: 'email', label: 'Work email', section: 'account',
width: 'half', rules: { required: true, email: true } },
{ name: 'password', type: 'password', label: 'Password', section: 'account',
width: 'half', rules: { required: true, minLength: 8 } },
{ name: 'tos', type: 'checkbox', label: 'I agree to the terms', section: 'account',
rules: { required: 'You must accept the terms.' } },
{ name: 'role', type: 'select', label: 'Role', section: 'workspace', width: 'half',
options: [{ label: 'Engineer', value: 'eng' }, { label: 'Designer', value: 'design' }],
rules: { required: true } },
{ name: 'seats', type: 'number', label: 'Seats', section: 'workspace', width: 'half',
min: 1, rules: { required: true, min: 1 } },
{ name: 'plan', type: 'radio', label: 'Plan', section: 'workspace', orientation: 'horizontal',
options: [{ label: 'Starter', value: 'starter' }, { label: 'Growth', value: 'growth' }],
rules: { required: true } },
{ name: 'bio', type: 'textarea', label: 'About your team', section: 'workspace',
autoGrow: true, maxLength: 160, showCount: true },
{ name: 'notifications', type: 'switch', label: 'Email me product updates', section: 'workspace' },
];
const sections: FormSection[] = [
{ id: 'account', title: 'Account', description: 'How you sign in.' },
{ id: 'workspace', title: 'Workspace', description: 'Set up your team.' },
];
<Form
columns={2}
fields={fields}
sections={sections}
submitLabel="Create account"
successMessage="Account created — check your inbox."
onSubmit={async (values) => { await api.register(values); }}
/>