Save Bar
A floating save bar that morphs like the Dynamic Island. Handles saving, a Saved check, errors with Try again and a nudge when someone tries to leave.
IslandBar is the save bar that floats at the bottom of a page while there's something to save. It's a dark pill that reads “Unsaved changes · Discard · Save ⌘S”. It rises from a small dot below the page and stretches sideways to fit its content, then shrinks back into the dot when there's nothing left to save.
Every state change is one shape changing size, the way the Dynamic Island does it. The bar animates its real width and height with springs generated from Apple's own spring equations, so the corners stay round at every frame and the text never stretches. It overshoots slightly as it grows and settles without a bounce as it shrinks. The old content blurs out while the new content sharpens in, a beat after the shape starts moving.
Saving shrinks the pill to a spinner. It stays there for at least 400ms so a fast save never flickers, then a check draws itself next to Saved and the bar leaves after 1.4 seconds. If the save fails, the pill widens into the error with Try again and Discard, and the draft is untouched. Edit during the Saved moment and it goes straight back to Unsaved changes.
When someone tries to leave with unsaved changes, call nudge(). The bar swells for a moment, the Save button rings, and screen readers hear why. useIslandBar wires most of this for you: it tracks the async save, binds ⌘S or Ctrl+S, asks the browser before the tab closes, and gives you guard() for links. With reduced motion turned on, the bar only fades: sizes snap and nothing bounces.
HextaUI Pro'yu alın
Tek bir ödeme, gelecekte eklenecekler dahil tüm blokların kilidini açar. Fiyatları görün.
Pro registry'yi components.json dosyasına ekleyin
components.json Token'ınızı ekleyin
Hesap sayfanızda bir token oluşturun ve
.env.localdosyasınaHEXTAUI_PRO_TOKENolarak ekleyin.Bloğu ekleyin
pnpm dlx shadcn@latest add @hextaui-pro/save-bar
Wire a form to your API
useIslandBar tracks saving, saved and error for you. Throw from onSave to show the message in the bar. The draft stays, and the error clears as soon as the value changes again.
Drive it from your own state
Pass status yourself when another hook already tracks saving. contained keeps the bar inside a framed editor, and actionsRef.nudge() bumps it when a link is blocked.
Batch changes with an extra control
The extra slot puts a control such as a reason Select between the message and the buttons. The bar grows to fit it and shrinks again when you save.
Yapı
Dıştan içe doğru birleştirdiğiniz parçalar.
| Parça | Açıklama |
|---|---|
IslandBar | The floating pill. It positions itself at the bottom center of the page, or inside the nearest positioned parent with contained, and renders the layer for the current status. |
Dirty layer | The message, an optional extra control, Discard and Save with its shortcut. |
Saving layer | A spinner and Saving… in a compact pill. |
Saved layer | A check that draws itself and Saved, held for 1.4 seconds before the bar leaves. |
Error layer | An icon, the error message, and Discard with Try again or your own errorActions. |
useIslandBar | A hook that turns dirty and an async onSave into the bar's status, with ⌘S, the leave guard and a ready-to-spread props object. |
IslandBar
The floating save bar. Other div props, ref and className go to the region element.
| Prop | Tür | Varsayılan |
|---|---|---|
statusWhat the bar shows. Saving is held for at least minSaving before Saved or the error, and Saved hides on its own after savedFor. | "hidden" | "dirty" | "saving" | "saved" | "error" | – |
messageThe text in the dirty state, such as “3 changes” or “Fix 2 fields to save”. | ReactNode | labels.unsaved |
iconAn icon before the dirty message. | ReactNode | – |
errorThe error message. A string is also announced to screen readers. | ReactNode | labels.error |
errorIconReplaces the red alert icon, for example with a warning triangle for a conflict. | ReactNode | <IconAlertCircle /> |
errorActionsReplaces Discard and Try again in the error state. Give the main button data-island-primary so focus can land on it. | ReactNode | – |
extraA control between the message and the buttons, shown in the dirty and error states. | ReactNode | – |
labelsregion, unsaved, saving, saved, error, save, discard, retry and nudge. | Partial<IslandBarLabels> | – |
shortcutThe shortcut shown on Save and in aria-keyshortcuts. The bar only displays it; bind it with useIslandBar or your own handler. Pass null to hide it. | string | null | "mod+s" |
saveDisabledDisables Save and Try again. | boolean | false |
onSaveCalled by Save. | () => void | – |
onDiscardCalled by Discard. Without it there's no Discard button. | () => void | – |
onRetryCalled by Try again. | () => void | onSave |
actionsRefExposes nudge({ kind?: "bump" | "shake", announce?: boolean, focus?: boolean }). | Ref<IslandBarActions> | – |
containedPositions the bar absolutely inside its nearest positioned parent instead of fixed to the viewport. | boolean | false |
announceRenders the live regions for Saving, Saved, errors and nudges. Turn it off when the page already announces these. | boolean | true |
minSavingThe minimum time in ms the saving state stays up before Saved or the error. | number | 400 |
savedForHow long in ms Saved stays up before the bar leaves. | number | 1400 |
useIslandBar
Tracks an async save for IslandBar. Returns status, error, blocked, save, discard, reset, nudge, guard, actionsRef and props to spread on IslandBar.
| Prop | Tür | Varsayılan |
|---|---|---|
dirtyWhether the form differs from what's saved. | boolean | – |
valueThe current draft. When it changes, an error or Saved state goes back to dirty. | unknown | – |
onSaveSaves the draft. Throw or reject to show the error; the message is shown in the bar. | () => unknown | – |
onDiscardResets the draft. Without it there's no Discard button. | () => void | – |
shortcutSaves from anywhere on the page while something is unsaved. | string | null | "mod+s" |
savedForHow long in ms the hook reports saved before it goes back to idle. | number | 1800 |
| Tuş | Action |
|---|---|
| ⌘S | Saves while something is unsaved, through useIslandBar. Ctrl+S on Windows and Linux. |
| Tab | Moves between the extra control, Discard and Save. |
| Enter | Odaktaki düğmeyi etkinleştirir. |
| Space | Odaktaki düğmeyi etkinleştirir. |
- The bar is a region landmark named “Unsaved changes” or your region label, so it can be found from the landmarks list.
- Only the current state's buttons can be focused. The layer that's fading out is inert and hidden from screen readers.
- If focus was inside the bar when its state changes, it moves to the new state's main button, or to the bar itself while saving.
- Saving, Saved and nudges are announced in a polite live region, and errors in an alert.
- Save carries aria-keyshortcuts for ⌘S and Ctrl+S. The key hint is hidden on touch screens and narrow bars.
- The bar keeps 44px buttons and a 48px pill on touch screens. With reduced motion it only fades: sizes snap and the nudge becomes a ring flash on Save.
- In forced colors mode the pill gets a system border.
Şunlarla geliştirildi
Save Bar bloğunun yapıldığı ücretsiz HextaUI bileşenleri. Her biri tek başına yüklenir.
Kod
4 dosya, components/blocks/save-bar konumuna eklendi.