Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,19 @@
- New `AutocompleteField` component for `type: 'autocomplete'`. Renders `<input>` + `<datalist>`.
- New `DateTimeField` component for `type: 'datetime'`. Renders `<input type="datetime-local">`.

### Migration notes

- **Drop the `next/dynamic({ ssr: false })` workaround** if you used it to avoid the prior SSR crash. `FormRenderer` now prerenders cleanly and hydrates without a layout shift:

```diff
- import dynamic from 'next/dynamic';
- const FormRenderer = dynamic(
- () => import('@formhaus/react').then((m) => m.FormRenderer),
- { ssr: false }
- );
+ import { FormRenderer } from '@formhaus/react';
```

## 0.3.1 - 2026-04-10

### Breaking
Expand Down
26 changes: 26 additions & 0 deletions docs/guide/fields.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,13 @@ Type-to-filter dropdown for long option lists. Default renderer uses `<input typ
}
```

::: warning Native `<datalist>` quirks
The default renderer uses the browser's `<datalist>` element. Two things to know:

1. **Filtering matches against `value`, not `label`.** Typing "Virginia" against `{ value: "us-east-1", label: "US East (N. Virginia)" }` shows nothing. If users will search by the label, swap the field to a custom component (MUI Autocomplete, Headless UI Combobox).
2. **The input does not enforce that the value is in the list.** Users can type anything. If you need "must be one of the options", add a custom validator or use a custom component.
:::

## Multiselect

Pick multiple from a list. Renders as a checkbox group. The value is an array of selected option values.
Expand Down Expand Up @@ -214,6 +221,25 @@ Date and time picker. Uses native `<input type="datetime-local">`. Emits `YYYY-M
}
```

::: warning Timezone gotcha
`<input type="datetime-local">` emits `YYYY-MM-DDTHH:mm` with **no timezone**. Most APIs expect ISO 8601 with a timezone offset (`2026-05-10T14:30:00Z` or `…+02:00`). If you POST the raw value to a backend that assumes UTC, you'll silently store the wrong instant for any user not in UTC.

Two ways to fix on submit:

```ts
function toISO(local: string): string {
return new Date(local).toISOString();
}

<FormRenderer
definition={definition}
onSubmit={(values) => api.post({ ...values, expiresAt: toISO(values.expiresAt as string) })}
/>
```

Or plug in a custom component (MUI `DateTimePicker`, react-aria `DateField`) that emits ISO directly.
:::

## File

File upload. Uses native file input. Set `accept` to restrict file types.
Expand Down
Loading