{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "form",
  "title": "Form",
  "type": "registry:ui",
  "files": [
    {
      "path": "packages/registry-svelte/components/form/Form.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { HTMLFormAttributes } from 'svelte/elements'\n  import type { TanstackFormApi } from './context'\n\n  export interface FormProps extends HTMLFormAttributes {\n    /** TanStack form instance from `createForm`. Structural divergence from\n     *  React is intentional: React's `Form` is a react-hook-form\n     *  `FormProvider` (no DOM, methods spread by the consumer), while Svelte\n     *  renders the `<form>` itself and takes the instance as a prop. */\n    form: TanstackFormApi\n    ref?: HTMLFormElement | null\n  }\n</script>\n\n<script lang=\"ts\">\n  import { setContext, untrack } from 'svelte'\n  import { cn } from '$lib/utils'\n  import { FORM_INSTANCE_CONTEXT_KEY } from './context'\n\n  let { class: className, form, children, ref = $bindable(null), ...restProps }: FormProps = $props()\n\n  // `untrack` — the form object identity is stable for the component's\n  // lifetime (created once by `createForm`), so initial capture is correct.\n  setContext(FORM_INSTANCE_CONTEXT_KEY, untrack(() => form))\n\n  function onSubmit(e: SubmitEvent) {\n    e.preventDefault()\n    e.stopPropagation()\n    void form.handleSubmit()\n  }\n</script>\n\n<form bind:this={ref} data-uipkge data-slot=\"form\" class={cn(className)} onsubmit={onSubmit} {...restProps}>\n  {@render children?.()}\n</form>\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/form/Form.svelte"
    },
    {
      "path": "packages/registry-svelte/components/form/FormActions.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { HTMLAttributes } from 'svelte/elements'\n\n  export interface FormActionsProps extends HTMLAttributes<HTMLDivElement> {\n    align?: 'left' | 'center' | 'right'\n    gap?: 'sm' | 'md' | 'lg'\n    ref?: HTMLDivElement | null\n  }\n</script>\n\n<script lang=\"ts\">\n  import { cn } from '$lib/utils'\n\n  let {\n    class: className,\n    align = 'right',\n    gap = 'md',\n    children,\n    ref = $bindable(null),\n    ...restProps\n  }: FormActionsProps = $props()\n\n  const alignClasses = {\n    left: 'justify-start',\n    center: 'justify-center',\n    right: 'justify-end',\n  }\n\n  const gapClasses = {\n    sm: 'gap-2',\n    md: 'gap-3',\n    lg: 'gap-4',\n  }\n</script>\n\n<div\n  bind:this={ref}\n  data-uipkge\n  data-slot=\"form-actions\"\n  class={cn('flex flex-wrap items-center', alignClasses[align], gapClasses[gap], className)}\n  {...restProps}\n>\n  {@render children?.()}\n</div>\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/form/FormActions.svelte"
    },
    {
      "path": "packages/registry-svelte/components/form/FormControl.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { Snippet } from 'svelte'\n\n  export interface FormControlBinding {\n    id: string\n    'aria-describedby': string\n    'aria-invalid': boolean\n    /** `form-control` data-slot, applied to the child control via spread —\n     *  the compat shim for React's `<Slot data-slot=\"form-control\">`, which\n     *  has no Svelte equivalent (this component renders no DOM of its own). */\n    'data-slot': 'form-control'\n  }\n\n  export interface FormControlProps {\n    /** Render-prop children (the Svelte counterpart of Radix `Slot`): spread\n     *  the binding onto your control —\n     *  `{#snippet children(props)}<Input {...props} />{/snippet}`. */\n    children?: Snippet<[FormControlBinding]>\n  }\n</script>\n\n<script lang=\"ts\">\n  import { useFormField } from './useFormField'\n\n  let { children }: FormControlProps = $props()\n\n  const { error, formItemId, formDescriptionId, formMessageId } = useFormField()\n\n  const binding = $derived<FormControlBinding>({\n    id: formItemId(),\n    'aria-describedby': !error() ? `${formDescriptionId()}` : `${formDescriptionId()} ${formMessageId()}`,\n    'aria-invalid': !!error(),\n    'data-slot': 'form-control',\n  })\n</script>\n\n{@render children?.(binding)}\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/form/FormControl.svelte"
    },
    {
      "path": "packages/registry-svelte/components/form/FormDescription.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { HTMLAttributes } from 'svelte/elements'\n\n  export interface FormDescriptionProps extends HTMLAttributes<HTMLParagraphElement> {\n    ref?: HTMLParagraphElement | null\n  }\n</script>\n\n<script lang=\"ts\">\n  import { cn } from '$lib/utils'\n  import { useFormField } from './useFormField'\n\n  let { class: className, children, ref = $bindable(null), ...restProps }: FormDescriptionProps = $props()\n\n  const { formDescriptionId } = useFormField()\n</script>\n\n<p\n  bind:this={ref}\n  id={formDescriptionId()}\n  data-uipkge\n  data-slot=\"form-description\"\n  class={cn('text-muted-foreground text-sm', className)}\n  {...restProps}\n>\n  {@render children?.()}\n</p>\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/form/FormDescription.svelte"
    },
    {
      "path": "packages/registry-svelte/components/form/FormField.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { Snippet } from 'svelte'\n  import type { TanstackFormApi } from './context'\n  import type { FormFieldBinding } from './FormFieldInner.svelte'\n\n  export interface FormFieldProps {\n    form?: TanstackFormApi\n    name: string\n    validators?: Record<string, unknown>\n    children?: Snippet<[FormFieldBinding]>\n  }\n</script>\n\n<script lang=\"ts\">\n  import { getContext } from 'svelte'\n  import FormFieldInner from './FormFieldInner.svelte'\n  import { FORM_INSTANCE_CONTEXT_KEY } from './context'\n\n  let { form, name, validators, children }: FormFieldProps = $props()\n\n  const injected = getContext<TanstackFormApi | undefined>(FORM_INSTANCE_CONTEXT_KEY)\n\n  const resolvedForm = $derived.by(() => {\n    const f = form ?? injected\n    if (!f) throw new Error('<FormField> requires a `form` prop or to be nested inside <Form form={...}>')\n    return f\n  })\n\n  const Field = $derived(resolvedForm.Field)\n</script>\n\n<Field {name} {validators}>\n  {#snippet children(field: any)}\n    <FormFieldInner {field}>\n      {#snippet children(binding)}\n        {@render children?.(binding)}\n      {/snippet}\n    </FormFieldInner>\n  {/snippet}\n</Field>\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/form/FormField.svelte"
    },
    {
      "path": "packages/registry-svelte/components/form/FormFieldInner.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { Snippet } from 'svelte'\n\n  export interface FieldMeta {\n    errors: Array<unknown>\n    errorMap?: Record<string, Array<unknown> | undefined>\n    isDirty: boolean\n    isTouched: boolean\n    isValid: boolean\n  }\n\n  export interface FieldApi {\n    name: string\n    state: {\n      value: unknown\n      meta: FieldMeta\n    }\n    handleChange: (v: unknown) => void\n    handleBlur: () => void\n  }\n\n  /** Spread onto a text-like control (`<Input {...componentField} />`). For\n   *  selects, checkboxes, or custom controls, wire `field.handleChange` /\n   *  `field.handleBlur` manually — also exposed on the binding. */\n  export interface ComponentField {\n    name: string\n    // `any` (not `unknown`) so `<Input {...componentField} />` spreads without\n    // a cast at every call site — TanStack field values are form-typed at the\n    // `createForm` call, which this structural binding cannot see.\n    value: any\n    oninput: (e: Event) => void\n    onblur: () => void\n  }\n\n  export interface FormFieldBinding {\n    field: FieldApi\n    componentField: ComponentField\n    error: string | undefined\n    valid: boolean\n    isDirty: boolean\n    isTouched: boolean\n  }\n\n  export interface FormFieldInnerProps {\n    field: FieldApi\n    children?: Snippet<[FormFieldBinding]>\n  }\n</script>\n\n<script lang=\"ts\">\n  import { setContext, untrack } from 'svelte'\n  import { FORM_FIELD_CONTEXT_KEY } from './context'\n\n  let { field, children }: FormFieldInnerProps = $props()\n\n  function formatError(raw: unknown): string {\n    if (typeof raw === 'string') return raw\n    if (raw && typeof raw === 'object' && 'message' in raw) {\n      return String((raw as { message: unknown }).message)\n    }\n    return String(raw)\n  }\n\n  // @tanstack/svelte-form state is runes-reactive, so plain `$derived`\n  // reads track value/meta updates — no manual store subscription needed\n  // (unlike the Vue twin, which snapshots via `store.subscribe`).\n  const error = $derived.by(() => {\n    const meta = field.state.meta\n    const flat = meta.errors\n    if (Array.isArray(flat) && flat.length > 0 && flat[0] != null) {\n      return formatError(flat[0])\n    }\n    const map = meta.errorMap ?? {}\n    for (const key of Object.keys(map)) {\n      const arr = map[key]\n      if (Array.isArray(arr) && arr.length > 0 && arr[0] != null) {\n        return formatError(arr[0])\n      }\n    }\n    return undefined\n  })\n\n  const valid = $derived(field.state.meta.isValid)\n  const isDirty = $derived(field.state.meta.isDirty)\n  const isTouched = $derived(field.state.meta.isTouched)\n\n  setContext(FORM_FIELD_CONTEXT_KEY, {\n    // `untrack` — the field name is static; error/valid/dirty/touched stay\n    // reactive through the getter closures below.\n    name: untrack(() => field.name),\n    error: () => error,\n    valid: () => valid,\n    isDirty: () => isDirty,\n    isTouched: () => isTouched,\n  })\n\n  const componentField = $derived<ComponentField>({\n    value: field.state.value,\n    oninput: (e: Event) => field.handleChange((e.target as HTMLInputElement).value),\n    onblur: () => field.handleBlur(),\n    name: field.name,\n  })\n\n  const binding = $derived<FormFieldBinding>({ field, componentField, error, valid, isDirty, isTouched })\n</script>\n\n{@render children?.(binding)}\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/form/FormFieldInner.svelte"
    },
    {
      "path": "packages/registry-svelte/components/form/FormItem.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { Snippet } from 'svelte'\n  import type { HTMLAttributes } from 'svelte/elements'\n  import type { FormStatus } from './types'\n\n  export interface FormItemProps extends HTMLAttributes<HTMLDivElement> {\n    label?: string\n    required?: boolean\n    description?: string\n    status?: FormStatus\n    help?: string\n    layout?: 'vertical' | 'horizontal'\n    labelWidth?: string\n    /** Extra content beside the label (replaces the Vue `label` slot). */\n    labelContent?: Snippet\n    ref?: HTMLDivElement | null\n  }\n\n  // Client-only counter for generated item ids. Assigned in onMount (never\n  // during SSR) so server and client markup stay identical.\n  let nextItemId = 0\n</script>\n\n<script lang=\"ts\">\n  import { onMount, setContext } from 'svelte'\n  import { cn } from '$lib/utils'\n  import { FORM_ITEM_CONTEXT_KEY } from './context'\n  import FormLabel from './FormLabel.svelte'\n\n  let {\n    class: className,\n    label,\n    required = false,\n    description,\n    status,\n    help,\n    layout = 'vertical',\n    labelWidth,\n    labelContent,\n    children,\n    ref = $bindable(null),\n    ...restProps\n  }: FormItemProps = $props()\n\n  let id = $state<string | undefined>(undefined)\n\n  // Getter (not the raw string): children initialize before onMount assigns\n  // the id, and `useFormField` resolves ids lazily through this.\n  setContext(FORM_ITEM_CONTEXT_KEY, () => id)\n\n  onMount(() => {\n    if (id === undefined) {\n      nextItemId += 1\n      id = `form-item-${nextItemId}`\n    }\n  })\n\n  const statusBorderClass = $derived.by(() => {\n    switch (status) {\n      case 'error':\n        return '[&_input]:border-destructive [&_textarea]:border-destructive [&_button]:border-destructive'\n      case 'warning':\n        return '[&_input]:border-warning [&_textarea]:border-warning [&_button]:border-warning'\n      case 'success':\n        return '[&_input]:border-success [&_textarea]:border-success [&_button]:border-success'\n      default:\n        return ''\n    }\n  })\n\n  const isHorizontal = $derived(layout === 'horizontal')\n</script>\n\n<div\n  bind:this={ref}\n  data-uipkge\n  data-slot=\"form-item\"\n  class={cn(\n    'grid gap-1.5',\n    isHorizontal && 'grid-cols-[var(--label-width,140px)_1fr] items-start gap-x-4 gap-y-0',\n    className,\n  )}\n  style:--label-width={labelWidth}\n  {...restProps}\n>\n  {#if label || labelContent}\n    <div class=\"flex items-center gap-1\">\n      {#if label}\n        <FormLabel for={`${id}-form-item`} class={status === 'error' ? 'text-destructive' : undefined}>\n          {label}\n        </FormLabel>\n      {/if}\n      {@render labelContent?.()}\n      {#if required}\n        <span class=\"text-destructive text-sm\" aria-hidden=\"true\">*</span>\n      {/if}\n    </div>\n  {/if}\n\n  <div class={cn('space-y-1', statusBorderClass)}>\n    {@render children?.()}\n    {#if description}\n      <p class=\"text-muted-foreground text-xs\">{description}</p>\n    {/if}\n    {#if help}\n      <p\n        class={cn('text-xs', {\n          'text-destructive': status === 'error',\n          'text-warning': status === 'warning',\n          'text-success': status === 'success',\n          'text-muted-foreground': !status,\n        })}\n        role={status === 'error' ? 'alert' : undefined}\n      >\n        {help}\n      </p>\n    {/if}\n  </div>\n</div>\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/form/FormItem.svelte"
    },
    {
      "path": "packages/registry-svelte/components/form/FormLabel.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { HTMLLabelAttributes } from 'svelte/elements'\n\n  export interface FormLabelProps extends HTMLLabelAttributes {\n    ref?: HTMLLabelElement | null\n  }\n</script>\n\n<script lang=\"ts\">\n  import { cn } from '$lib/utils'\n  import { Label } from '$lib/components/ui/label'\n  import { useFormField } from './useFormField'\n\n  let { class: className, children, ref = $bindable(null), ...restProps }: FormLabelProps = $props()\n\n  const { error, formItemId } = useFormField()\n</script>\n\n<Label\n  data-uipkge\n  data-slot=\"form-label\"\n  data-error={!!error()}\n  class={cn('data-[error=true]:text-destructive', className)}\n  bind:ref\n  {...restProps}\n  for={formItemId()}\n>\n  {@render children?.()}\n</Label>\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/form/FormLabel.svelte"
    },
    {
      "path": "packages/registry-svelte/components/form/FormMessage.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { HTMLAttributes } from 'svelte/elements'\n\n  export interface FormMessageProps extends HTMLAttributes<HTMLParagraphElement> {\n    ref?: HTMLParagraphElement | null\n  }\n</script>\n\n<script lang=\"ts\">\n  import { cn } from '$lib/utils'\n  import { useFormField } from './useFormField'\n\n  let { class: className, children, ref = $bindable(null), ...restProps }: FormMessageProps = $props()\n\n  const { error, formMessageId } = useFormField()\n</script>\n\n{#if error()}\n  <p\n    bind:this={ref}\n    id={formMessageId()}\n    data-uipkge\n    data-slot=\"form-message\"\n    role=\"alert\"\n    class={cn('text-destructive text-sm', className)}\n    {...restProps}\n  >\n    {error()}\n  </p>\n{/if}\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/form/FormMessage.svelte"
    },
    {
      "path": "packages/registry-svelte/components/form/FormSection.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { HTMLAttributes } from 'svelte/elements'\n\n  export interface FormSectionProps extends HTMLAttributes<HTMLDivElement> {\n    title?: string\n    subtitle?: string\n    description?: string\n    divider?: boolean\n    headingLevel?: 'h2' | 'h3' | 'h4' | 'h5'\n    ref?: HTMLDivElement | null\n  }\n</script>\n\n<script lang=\"ts\">\n  import { cn } from '$lib/utils'\n\n  let {\n    class: className,\n    title,\n    subtitle,\n    description,\n    divider = false,\n    headingLevel = 'h4',\n    children,\n    ref = $bindable(null),\n    ...restProps\n  }: FormSectionProps = $props()\n</script>\n\n<div bind:this={ref} data-uipkge data-slot=\"form-section\" class={cn('space-y-3', className)} {...restProps}>\n  {#if divider || title || subtitle}\n    <div class={divider ? 'border-t pt-4' : undefined}>\n      {#if title || subtitle}\n        <div class=\"space-y-1\">\n          {#if title}\n            <svelte:element this={headingLevel} class=\"text-sm font-semibold\">{title}</svelte:element>\n          {/if}\n          {#if subtitle}\n            <p class=\"text-muted-foreground text-xs\">{subtitle}</p>\n          {/if}\n        </div>\n      {/if}\n    </div>\n  {/if}\n  {#if description}\n    <p class=\"text-muted-foreground text-xs\">{description}</p>\n  {/if}\n  {@render children?.()}\n</div>\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/form/FormSection.svelte"
    },
    {
      "path": "packages/registry-svelte/components/form/FormStatus.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { HTMLAttributes } from 'svelte/elements'\n  import type { FormStatus } from './types'\n\n  export interface FormStatusProps extends HTMLAttributes<HTMLDivElement> {\n    status: FormStatus\n    message: string\n    ref?: HTMLDivElement | null\n  }\n</script>\n\n<script lang=\"ts\">\n  import type { Component } from 'svelte'\n  import { CircleAlert, CircleCheck, TriangleAlert } from '@lucide/svelte'\n  import { cn } from '$lib/utils'\n\n  let { class: className, status, message, ref = $bindable(null), ...restProps }: FormStatusProps = $props()\n\n  const statusConfig: Record<NonNullable<FormStatus>, { icon: Component<any>; container: string }> = {\n    error: {\n      icon: CircleAlert,\n      container: 'bg-destructive/10 text-destructive border-destructive/20',\n    },\n    warning: {\n      icon: TriangleAlert,\n      container: 'bg-warning/10 text-warning border-warning/30',\n    },\n    success: {\n      icon: CircleCheck,\n      container: 'bg-success/10 text-success border-success/30',\n    },\n  }\n\n  const Icon = $derived(status ? statusConfig[status].icon : null)\n  const containerClass = $derived(status ? statusConfig[status].container : '')\n</script>\n\n{#if status && Icon}\n  <div\n    bind:this={ref}\n    data-uipkge\n    data-slot=\"form-status\"\n    role={status === 'error' ? 'alert' : 'status'}\n    class={cn('flex items-center gap-2 rounded-md border px-3 py-2 text-sm', containerClass, className)}\n    {...restProps}\n  >\n    <Icon class=\"size-4 shrink-0\" aria-hidden=\"true\" />\n    <span>{message}</span>\n  </div>\n{/if}\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/form/FormStatus.svelte"
    },
    {
      "path": "packages/registry-svelte/components/form/index.ts",
      "content": "export { default as Form, type FormProps } from './Form.svelte'\nexport { default as FormField, type FormFieldProps } from './FormField.svelte'\nexport {\n  default as FormFieldInner,\n  type ComponentField,\n  type FieldApi,\n  type FieldMeta,\n  type FormFieldBinding,\n  type FormFieldInnerProps,\n} from './FormFieldInner.svelte'\nexport { default as FormControl, type FormControlBinding, type FormControlProps } from './FormControl.svelte'\nexport { default as FormDescription, type FormDescriptionProps } from './FormDescription.svelte'\nexport { default as FormItem, type FormItemProps } from './FormItem.svelte'\nexport { default as FormLabel, type FormLabelProps } from './FormLabel.svelte'\nexport { default as FormMessage, type FormMessageProps } from './FormMessage.svelte'\nexport { default as FormActions, type FormActionsProps } from './FormActions.svelte'\nexport { default as FormSection, type FormSectionProps } from './FormSection.svelte'\nexport { default as FormStatus, type FormStatusProps } from './FormStatus.svelte'\nexport { useFormField } from './useFormField'\nexport { FORM_ITEM_CONTEXT_KEY, FORM_FIELD_CONTEXT_KEY, FORM_INSTANCE_CONTEXT_KEY } from './context'\nexport type { FormFieldContext, TanstackFormApi } from './context'\nexport type { FormStatus as FormStatusValue } from './types'\nexport { createForm } from '@tanstack/svelte-form'\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/form/index.ts"
    },
    {
      "path": "packages/registry-svelte/components/form/context.ts",
      "content": "import type { Component } from 'svelte'\n\nexport const FORM_ITEM_CONTEXT_KEY = Symbol('form-item')\n\nexport interface FormFieldContext {\n  name: string\n  error: () => string | undefined\n  valid: () => boolean\n  isDirty: () => boolean\n  isTouched: () => boolean\n}\n\nexport const FORM_FIELD_CONTEXT_KEY = Symbol('form-field')\n\nexport interface TanstackFormApi {\n  Field: Component<any>\n  handleSubmit: () => void | Promise<void>\n}\n\nexport const FORM_INSTANCE_CONTEXT_KEY = Symbol('form-instance')\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/form/context.ts"
    },
    {
      "path": "packages/registry-svelte/components/form/types.ts",
      "content": "export type FormStatus = 'error' | 'warning' | 'success' | null | undefined\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/form/types.ts"
    },
    {
      "path": "packages/registry-svelte/components/form/useFormField.ts",
      "content": "import { getContext } from 'svelte'\nimport { FORM_FIELD_CONTEXT_KEY, FORM_ITEM_CONTEXT_KEY, type FormFieldContext } from './context'\n\nexport function useFormField() {\n  const fieldContext = getContext<FormFieldContext | undefined>(FORM_FIELD_CONTEXT_KEY)\n  const getItemId = getContext<(() => string | undefined) | undefined>(FORM_ITEM_CONTEXT_KEY)\n\n  if (!fieldContext) throw new Error('useFormField should be used within <FormField>')\n\n  // Id getters (not plain strings): FormItem assigns its id in onMount so SSR\n  // markup stays identical between server and client. Call these inside\n  // `$derived` or the template and they track the assignment.\n  const formItemId = () => `${getItemId?.()}-form-item`\n  const formDescriptionId = () => `${getItemId?.()}-form-item-description`\n  const formMessageId = () => `${getItemId?.()}-form-item-message`\n\n  return {\n    id: getItemId,\n    name: () => fieldContext.name,\n    formItemId,\n    formDescriptionId,\n    formMessageId,\n    valid: fieldContext.valid,\n    isDirty: fieldContext.isDirty,\n    isTouched: fieldContext.isTouched,\n    error: fieldContext.error,\n  }\n}\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/form/useFormField.ts"
    }
  ],
  "dependencies": [
    "@tanstack/svelte-form",
    "@lucide/svelte"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/svelte/label.json"
  ],
  "description": "Zod-first form block built on TanStack Svelte Form. Wires field labels, descriptions, error messages, and validation together; bind a field once and the rest is automatic.",
  "categories": [
    "form"
  ]
}