SvForm

A schema-driven form that renders the SvGrid UI-kit controls from a FormField[], with labels, required and custom validation, and a submit handler.

SvForm turns a declarative field list into a laid-out form - text, email, tel, textarea, number, password, select, checkbox, switch, date, color, and rating fields all map to the kit's editors. It validates on blur and on submit, emits onSubmit(values) only when valid, and onChange(values) on every edit. Colors come from the grid's --sg-* tokens, so it matches the rest of the kit.

Basic usage

<script lang="ts">
  import { SvForm, type FormField } from '@svgrid/grid'
  const fields: FormField[] = [
    { name: 'name', label: 'Full name', required: true },
    { name: 'email', label: 'Email', type: 'email', required: true },
    { name: 'plan', label: 'Plan', type: 'select',
      options: [{ value: 'free', label: 'Free' }, { value: 'pro', label: 'Pro' }] },
    { name: 'agree', label: 'I accept the terms', type: 'checkbox' },
  ]
</script>

<SvForm {fields} columns={2} onSubmit={(values) => save(values)} />

Props

Prop Type Default Description
fields ReadonlyArray<FormField> - The form schema. See FormField.
initial Record<string, any> {} Initial values, seeded once on mount.
onSubmit (values: Record<string, any>) => void - Fired with the values when the form is valid.
onChange (values: Record<string, any>) => void - Fired on every field edit.
submitLabel string Submit Label for the submit button.
columns number 1 Columns in the responsive field grid.
disabled boolean false Disable every field and the submit button.

FormField

type FormFieldType =
  | 'text' | 'email' | 'tel' | 'textarea' | 'number' | 'password'
  | 'select' | 'checkbox' | 'switch' | 'date' | 'color' | 'rating'

type FormField = {
  name: string
  label: string
  type?: FormFieldType                 // defaults to 'text'
  required?: boolean
  placeholder?: string
  options?: Array<{ value: string | number; label: string }>  // for 'select'
  rules?: ReadonlyArray<Validator>     // declarative rules (email/pattern/min/compare...)
  validate?: (value: any, values: Record<string, any>) => string | null | undefined
  full?: boolean                       // span the full width in the grid
}

Patterns

Two-column layout with full-width rows

Set columns={2} and mark wide fields full so they span both columns:

const fields: FormField[] = [
  { name: 'first', label: 'First name', required: true },
  { name: 'last', label: 'Last name', required: true },
  { name: 'bio', label: 'Bio', type: 'textarea', full: true },
]

Cross-field validation

validate receives the whole values object, so one field can check another - for example confirming a password:

{ name: 'confirm', label: 'Confirm password', type: 'password', required: true,
  validate: (v, values) => (v === values.password ? null : 'Passwords do not match') }

Declarative rules

Use rules for reusable checks (email, pattern, min, compare) instead of hand writing validate. Required, rules, then validate run in that order, and the first failure wins.

Sign-up form with declarative rules

Compose rules per field rather than hand-writing validate. compare reads another field for a cross-field check, so it confirms the password inline:

<script lang="ts">
  import { SvForm, rules, type FormField } from '@svgrid/grid'
  const fields: FormField[] = [
    { name: 'email', label: 'Email', type: 'email', required: true, rules: [rules.email()] },
    { name: 'password', label: 'Password', type: 'password', required: true,
      rules: [rules.minLength(8)] },
    { name: 'confirm', label: 'Confirm password', type: 'password', required: true,
      rules: [rules.compare('password', '===', { message: 'Passwords do not match' })] },
    { name: 'age', label: 'Age', type: 'number', rules: [rules.min(18)] },
  ]
</script>

<SvForm {fields} columns={2} submitLabel="Create account"
  onSubmit={(values) => register(values)} />

Tip: every rule builder except required skips empty values, so rules.min(18) only fires once the optional age field is filled - add required when the field must also be present.

Accessibility

See also