Dynamic Form Section

Installation

Run the following command

npx vibes@latest add dynamic-form-section

Usage

import { DynamicFormSection } from '@/vibes/soul/sections/dynamic-form-section';function Usage() {  return (      <DynamicFormSection          action={action}          fields={fields}          subtitle="Register an account with us to get updates and track your orders."          title="Sign up"      />  );}export const fields = [  { type: 'email', label: 'Email', name: 'email', required: true },  { type: 'password', label: 'Password', name: 'password', required: true },  { type: 'confirm-password', label: 'Confirm password', name: 'confirm-password', required: true },]export async function action(  prevState: { fields: Array<Field | FieldGroup<Field>>; lastResult: SubmissionResult | null },  payload: FormData,) {  'use server';  const submission = parseWithZod(payload, { schema: schema(prevState.fields) });  if (submission.status !== 'success') {    return {      fields: prevState.fields,      lastResult: submission.reply({ formErrors: ['Boom!'] }),    };  }  await new Promise((resolve) => setTimeout(resolve, 1000));  return {    fields: prevState.fields,    lastResult: submission.reply({ resetForm: true }),  };}

API Reference

DynamicFormSectionProps

PropTypeDefault
title
string
subtitle
string
action*
DynamicFormAction<F>
fields*
Array<F | FieldGroup<F>>
submitLabel
string
className
string

DynamicFormAction

interface State<F extends Field> {  fields: Array<F | FieldGroup<F>>;  lastResult: SubmissionResult | null;}export type DynamicFormAction<F extends Field> = Action<State<F>, FormData>;

This component uses Confom to handle form submissions. Refer to the Conform docs for more details.

Here's an example of an action function that does validation and simulates signing up a new user:

export async function action(  prevState: { fields: Array<Field | FieldGroup<Field>>; lastResult: SubmissionResult | null },  payload: FormData,) {  'use server';  const submission = parseWithZod(payload, { schema: schema(prevState.fields) });  if (submission.status !== 'success') {    return {      fields: prevState.fields,      lastResult: submission.reply({ formErrors: ['Boom!'] }),    };  }  await new Promise((resolve) => setTimeout(resolve, 1000));  return {    fields: prevState.fields,    lastResult: submission.reply({ resetForm: true }),  };}

CSS Variables

This component supports various CSS variables for theming. Here's a comprehensive list.

:root {  --dynamic-form-font-family: var(--font-family-body);  --dynamic-form-title-font-family: var(--font-family-heading);  --dynamic-form-title: var(--foreground);  --dynamic-form-subtitle: var(--contrast-500);}