# Unsaved Changes Bar

> A floating bar for settings pages and editors. It rises when a form is dirty, counts the changed fields, saves with ⌘S, shows a spinner, an error that keeps the changes, or Saved before it sinks away. Bump attention when someone tries to leave and it shakes and flashes; it also asks before a reload or close. Ships useFormDraft for draft-versus-saved form state.

- Slug: `unsaved-changes-bar`
- Category: [Forms](https://www.assembli.design/category/forms.md)
- Type: component
- Tags: unsaved-changes, save-bar, settings, dirty-state, form, shortcut, discard
- npm dependencies: lucide-react, motion
- shadcn/ui dependencies: none
- Live preview: https://www.assembli.design/preview/unsaved-changes-bar
- Page: https://www.assembli.design/components/unsaved-changes-bar

![Unsaved Changes Bar preview](https://www.assembli.design/thumbnails/unsaved-changes-bar-light.png)

## Props

Other props pass through to the root element.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `dirty` (required) | `boolean` |  | Show the bar. It stays up through saving and a short "Saved" after this turns false. |
| `onSave` (required) | `() => void \| Promise<unknown>` |  | Return a promise to show a spinner; a rejection shows the error and keeps the changes. |
| `onDiscard` (required) | `() => void` |  |  |
| `changes` | `number` |  | How many fields changed, for "3 unsaved changes". |
| `message` | `React.ReactNode` |  |  |
| `saveLabel` | `string` | `"Save changes"` |  |
| `discardLabel` | `string` | `"Discard"` |  |
| `attention` | `number` | `0` | Bump this to nudge the bar, e.g. when someone tries to leave the page with changes. |
| `strategy` | `"fixed" \| "absolute"` | `"fixed"` | `fixed` floats over the viewport; `absolute` sits at the bottom of the nearest positioned parent. |
| `warnOnLeave` | `boolean` | `true` | Ask the browser to confirm before the tab closes or reloads while dirty. |
| `shortcut` | `boolean` | `true` | Save with ⌘S / Ctrl+S anywhere on the page while dirty. |

## Install

One-time setup (needs a subscription):

1. Add the registry to the project's `components.json`: `{"@assembli":{"url":"https://www.assembli.design/r/{name}.json","headers":{"Authorization":"Bearer ${ASSEMBLI_API_KEY}"}}}` (merge into `"registries"`).
2. Put an API key from https://www.assembli.design/account in `.env.local` as `ASSEMBLI_API_KEY=asm_…`.

Then install with the shadcn CLI (writes `components/unsaved-changes-bar/unsaved-changes-bar.tsx` and installs dependencies):

```bash
npx shadcn@latest add @assembli/unsaved-changes-bar
```

Registry item JSON: https://www.assembli.design/r/unsaved-changes-bar.json (send `Authorization: Bearer <api key>`)

## Code

> Component source needs an Assembli subscription ($12/month or $96/year) and an API key sent as `Authorization: Bearer <key>`. To get one without copying anything, POST https://www.assembli.design/api/agent/login (or call the MCP tool connect_account), show the user the link it returns, and poll https://www.assembli.design/api/agent/token for the key. Or subscribe at https://www.assembli.design/pricing and create a key at https://www.assembli.design/account.
