# Form Dialog (`form-dialog`) - SignalOS widget

> Generic modal container for form content, with confirm/cancel actions, configurable sizes, a submitting (loading) state, and an optional DynamicForm renderer driven by a field config array.

- **Version:** 0.4.4
- **Kind:** widget · **Category:** layout
- **Install:** `npx shadcn@latest add @signalos/form-dialog`
- **Registry dependencies (pulled automatically):** @signalos/tokens, @signalos/utils, @signalos/button, @signalos/checkbox, @signalos/dialog, @signalos/input, @signalos/label, @signalos/select, @signalos/switch, @signalos/textarea, @signalos/scroll-area
- **npm dependencies:** lucide-react@^1.7.0
- **Files installed:** `src/components/widgets/form-dialog/FormDialog.tsx`, `src/components/widgets/form-dialog/FormDialog.types.ts`, `src/components/widgets/form-dialog/FormDialog.constants.ts`, `src/components/widgets/form-dialog/DynamicForm.tsx`, `src/components/widgets/form-dialog/DynamicForm.types.ts`, `src/components/widgets/form-dialog/DynamicForm.constants.ts`, `src/components/widgets/form-dialog/FieldRenderer.tsx`

## Access

This is a private registry: pulling source requires a `SIGNALOS_REGISTRY_TOKEN`
(GitHub fine-grained PAT with read access to the signal-widgets repo) and an
`@signalos` entry in components.json `"registries"`. Previews and this document are public.

## Usage

```tsx
import { FormDialog } from "@/components/widgets/form-dialog/FormDialog"
```

## Example

```tsx
// Example: form dialog with two inputs and a save action.
import { useState } from "react"

import { FormDialog } from "@/components/widgets/form-dialog/FormDialog"

export default function Example() {
  const [open, setOpen] = useState(false)

  return (
    <FormDialog
      open={open}
      onOpenChange={setOpen}
      title="Create User"
      description="Enter the user details below."
      onSubmit={() => console.info("submitted")}
    >
      <input placeholder="Name" />
      <input placeholder="Email" />
    </FormDialog>
  )
}
```

## Props

### `FormDialogSize`

```ts
export type FormDialogSize =
  "sm" | "md" | "lg" | "xl" | "2xl" | "3xl" | "4xl" | "5xl" | "full"
```

### `FormDialogProps`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `open` | `boolean \| undefined` | no | - |  |
| `onOpenChange` | `(open: boolean) => void` | yes | - |  |
| `title` | `string` | yes | - |  |
| `description` | `ReactNode` | no | - |  |
| `children` | `ReactNode` | no | - |  |
| `onSubmit` | `() => void` | yes | - |  |
| `isSubmitting` | `boolean \| undefined` | no | - |  |
| `submitLabel` | `string \| undefined` | no | - |  |
| `cancelLabel` | `string \| undefined` | no | - |  |
| `size` | `FormDialogSize \| undefined` | no | - |  |
| `contentClassName` | `string \| undefined` | no | - |  |
| `dialogTestId` | `string \| undefined` | no | - |  |
| `submitTestId` | `string \| undefined` | no | - |  |
| `cancelTestId` | `string \| undefined` | no | - |  |
| `titleTestId` | `string \| undefined` | no | - |  |
| `footer` | `ReactNode` | no | - |  |
| `contentProps` | `Record<string, string \| number \| boolean \| undefined> \| undefined` | no | - |  |
| `fields` | `FieldConfig[] \| undefined` | no | - |  |
| `sections` | `FormSection[] \| undefined` | no | - |  |
| `values` | `T \| undefined` | no | - |  |
| `onChange` | `((values: T) => void) \| undefined` | no | - |  |

## Changelog

## 0.4.4

- Fix cross-item imports to use canonical @/components paths; add missing signalos.category to manifests.

# form-dialog
## 0.4.3
- format the code
## 0.4.2

- Add `"use client"` directive to `FormDialog.tsx`.
- Wrap dialog body in `ScrollArea` (max-h-[70vh]) so long forms scroll within the modal.
- Make `FormDialog` generic (`<T extends Record<string, unknown>>`) so `values`/`onChange` are typed end-to-end.
- Add `titleTestId` prop (default `"form-dialog-title"`) for targeting the dialog title in tests.

## 0.4.1

- Add `DynamicForm` component: renders fields driven by a `FieldConfig[]` or
  `FormSection[]` config array with responsive 12-column grid layout and
  conditional visibility support.
- Add `FieldRenderer` with a renderer registry covering `input`, `password`,
  `number`, `email`, `url`, `date`, `textarea`, `select`, `checkbox`, `switch`,
  `radio`, and `custom` field types.
- `FormDialog` now accepts optional `fields`, `sections`, `values`, and
  `onChange` props; when provided the dialog body renders `DynamicForm`
  automatically instead of `children`.
- `children` made optional (was required).

## 0.2.1

- Add `footer` prop to override or hide the default Cancel/Submit footer, and
  `contentProps` to pass extra attributes through to the dialog content.
- Content sync fix to bring source in line with published registry payload.

## 0.1.0

- Initial release: generic modal container for form content with confirm/cancel
  actions, configurable sizes, and a submitting (loading) state.
