Publish bar
The toolbar of a publishable editor screen. It sits directly under the TopBar with the section title on the left and, on the right, the publish state plus a single Review & publish action. Everything on the right is driven by dirty: unsaved changes enable the action and swap the label; a clean state shows Published with a green dot and the action off.
Live preview
Payment method settings
import { PublishBar } from "@/components/organisms/publish-bar";
<PublishBar
title="Payment method settings"
dirty={hasUnsavedChanges}
onPublish={openPublishReview}
/>Anatomy
A slim h-16 bar (the 64px shell rhythm) with a bottom border. Left: the section title (text-lg semibold). Right: the publish status followed by the primary action. There is exactly one action here — anything more belongs in a separate toolbar row.
Payment method settings
- 1Section title
h1, text-lg semibold, truncates. The name of the section being edited (e.g. Payment method settings).
- 2Publish status
Muted text driven by dirty: 'Unsaved changes' when dirty, or 'Published' with a green dot when clean. Never red — it is informational, not an error.
- 3Primary action
A single Button (Review & publish). Enabled only while dirty; disabled (and lavender) when everything is already published.
Common configurations
Three canonical states: an editor with unsaved changes (the action is live), a clean published editor (the action rests, disabled), and the same bar reused on another publishable section with a custom action label.
The default working state while a user edits. Status reads 'Unsaved changes' and the Review & publish action is enabled.
Payment method settings
<PublishBar
title="Payment method settings"
dirty
onPublish={openPublishReview}
/>Nothing pending. Status shows 'Published' with a green dot and the action is disabled until the next edit makes the section dirty again.
Styling
<PublishBar title="Styling" />The same bar on Routing with actionLabel overridden to 'Publish changes'. This is why it lives in the kit and not inline in one screen.
Routing rules
<PublishBar
title="Routing rules"
dirty
actionLabel="Publish changes"
onPublish={publish}
/>Import
Copy this import at the top of the file. PublishBar is self-contained chrome — give it a title, a dirty flag, and an onPublish handler.
import { PublishBar } from "@/components/organisms/publish-bar";Props
PublishBar is driven by one flag: dirty. Pass the title, wire onPublish, and optionally override the status / action labels. Everything else (height, border, the disabled logic) is canonical.
| Prop | Type | Default | Description |
|---|---|---|---|
| title | string | — | Section / page title on the left. |
| dirty | boolean | false | Whether there are unsaved changes. Drives the status label AND enables/disables the action. |
| unsavedLabel | string | 'Unsaved changes' | Status label shown when dirty is true. |
| publishedLabel | string | 'Published' | Status label (with a green dot) shown when dirty is false. |
| actionLabel | string | 'Review & publish' | Label of the primary action button. |
| onPublish | () => void | — | Fires when the primary action is clicked (only enabled while dirty). |
| className | string | — | Merged onto the bar via cn(). Layout (h-16, border-b, px-6) is canonical. |
When to use
- The top of any section a user edits and then publishes: Checkout Builder, Routing, Styling.
- Whenever a screen needs a persistent 'you have unsaved changes → publish' affordance across its sub-views.
- Directly under the TopBar, spanning the full width above a two-column editor body.
When not to use
- As a page intro with a greeting or subtitle — that is PageHeader.
- For a toolbar with many controls (filters, tabs, multiple buttons) — use a dedicated toolbar row.
- For destructive confirmations — publishing is not a delete; use a Dialog for those.
Usage
- Drive the whole bar from a single dirty flag so the label and the button stay in sync.
- Keep exactly one primary action — Review & publish.
- Keep the status muted; the green dot on Published is the only color it carries.
- Don't add a Discard / secondary button here — this bar publishes, it doesn't manage per-change undo.
- Don't turn the status red for 'Unsaved changes' — it is informational, not an error.
- Don't confuse it with PageHeader — this is chrome for an editor, not a page greeting.
Related
Cross-links to atoms and patterns you may reach for next.
- Page headerThe tall page intro (greeting + subtitle + badge). PublishBar is the slim editor toolbar, not a page intro.
- Top barShell chrome above it; PublishBar stacks directly underneath.
- ButtonThe primary Review & publish action.
- Checkout builder cardThe payment-method rows edited on the screen this bar publishes.