Organisms

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.

Updated Jul 27, 2026 by Juan Pablo Turina

Live preview

Payment method settings

Unsaved changes
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

Unsaved changes
  1. 1
    Section title

    h1, text-lg semibold, truncates. The name of the section being edited (e.g. Payment method settings).

  2. 2
    Publish 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.

  3. 3
    Primary 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.

Unsaved changes (dirty)

The default working state while a user edits. Status reads 'Unsaved changes' and the Review & publish action is enabled.

Payment method settings

Unsaved changes
<PublishBar
  title="Payment method settings"
  dirty
  onPublish={openPublishReview}
/>
Published (clean)

Nothing pending. Status shows 'Published' with a green dot and the action is disabled until the next edit makes the section dirty again.

Styling

Published
<PublishBar title="Styling" />
Reused on another section

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

Unsaved changes
<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.

Self-contained chrome — pass a title + dirty state + onPublish. It composes the kit Button and tokens; no provider needed.
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.

PropTypeDefaultDescription
titlestringSection / page title on the left.
dirtybooleanfalseWhether there are unsaved changes. Drives the status label AND enables/disables the action.
unsavedLabelstring'Unsaved changes'Status label shown when dirty is true.
publishedLabelstring'Published'Status label (with a green dot) shown when dirty is false.
actionLabelstring'Review & publish'Label of the primary action button.
onPublish() => voidFires when the primary action is clicked (only enabled while dirty).
classNamestringMerged 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

Do
  • 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
  • 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.