Tab Collision

Lets only one browser tab edit a record at a time, so a save in one tab doesn't silently erase edits in another.

StopsSecond tab save erased edits

Installation

pnpm dlx shadcn@latest add https://bollard-ui.vercel.app/r/tab-collision.json

The files land in your project. They're yours to edit.

Usage

tab-collision-usage.tsx
import { TabCollision } from "@/components/ui/tab-collision"

<TabCollision recordId="demo-invoice-1042" dirty={amount !== "48,500.00"}>
  <label className="grid gap-1.5 text-sm font-medium">
    Amount (₹)
    <input value={amount} onChange={(event) => setAmount(event.target.value)} inputMode="decimal" className={field} />
  </label>
</TabCollision>

What it catches

  • The same record open for editing in another tab of this browser
  • Taking over while the other tab has unsaved changes (confirm first)
  • Status changes reported through onStatusChange

Props

TabCollision props
PropTypeDefault
recordId* (required)

Identifies the record; tabs editing different records never collide.

string—
dirty

Whether this tab has unsaved changes. A newer tab won't take over a dirty one without asking.

booleanfalse
onStatusChange

Called whenever this tab gains or loses the right to edit.

(status: TabStatus) => void—
message

Shown when another tab is editing.

string"Open in another tab. Editing is paused here so the two c…
dirtyMessage

Shown when the other tab has unsaved changes.

string"Open in another tab with unsaved changes. Editing is pau…
confirmMessage

Confirmation before taking over.

string"The other tab keeps its unsaved changes but becomes read…
takeOverLabel

Label of the Use-this-tab button.

string"Use this tab"
confirmLabel

Label of the confirm-take-over button.

string"Take over anyway"
cancelLabel

Label of the Cancel button.

string"Cancel"
regionLabel

Accessible name of the notice.

string"Open in another tab"

* required. Also accepts the native props of <fieldset> (className, aria-*, data-*…), passed through to it.

Accessibility

  • Notice is a region with an aria-label; message in a polite live region
  • Confirm step closes with Escape
  • Buttons have text labels; icons are aria-hidden

Only what the source does. Test with your own screen reader and content before shipping.

Limitations

This is a UX guard rail. Enforce on the server: Use optimistic concurrency (version or ETag) on save so concurrent edits from anywhere are rejected, not overwritten.

  • Same browser profile only; other devices, browsers or users are not seen
  • Read-only mode is up to you to apply using the status
  • Does not merge edits

What it stops

Second tab save erased edits

Also known as

multiple tabs · broadcastchannel · concurrent edit · conflict · read only · edit lock · cross-tab

Dependencies

Pairs well with