Conflict Banner

Names who changed a record while you were editing and shows the difference, so nobody silently overwrites a teammate's edit.

StopsOverwrote a teammate's edit

Release notes

Launch is planned for 14 November. Marketing owns the press release and the landing page.

Installation

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

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

Usage

conflict-banner-usage.tsx
import { ConflictBanner } from "@/components/ui/conflict-banner"

<ConflictBanner
  yourVersion={yours}
  theirVersion={theirs}
  editor="Priya"
  editedAt={editedAt}
  onKeepMine={() => setResolved("mine")}
  onUseTheirs={() => setResolved("theirs")}
/>

What it catches

  • Saving over a newer version from someone else
  • Unseen differences, via a word diff
  • How much of the other person's work "Keep mine" would discard
  • Versions that turn out to be identical

Props

ConflictBanner props
PropTypeDefault
yourVersion* (required)

The text you were editing.

string—
theirVersion* (required)

The text now saved on the server by someone else.

string—
editor* (required)

Who saved the other version, e.g. "Priya".

string—
editedAt* (required)

When they saved it.

Date | number | string—
onKeepMine* (required)

Overwrite their version with yours.

() => void—
onUseTheirs* (required)

Drop your edits and load theirs.

() => void—
message

Templates: `{editor}`, `{when}` and `{count}` ("3 words") are filled in.

string"{editor} edited this {when} while you were working."
identicalText

Shown when both versions are the same.

string"{editor} edited this {when}. Their version matches yours."
confirmText

Overwrite confirmation text ({count} words are filled in).

string"Keeping yours replaces {count} {editor} wrote."
compareLabel

Text for the compare toggle.

string"Compare"
useTheirsLabel

Text for the use-theirs button.

string"Use theirs"
keepMineLabel

Text for the keep-mine button.

string"Keep mine"
overwriteLabel

Text for the confirm-overwrite button.

string"Overwrite {editor}'s edit"
cancelLabel

Text for the cancel button.

string"Cancel"
dismissLabel

Text for the dismiss button.

string"Got it"
locale

Locale for "4 min ago". Defaults to the browser's.

string—
justNowLabel

Shown instead of a time for edits under a minute old.

string"just now"
regionLabel

Accessible name of the banner. `{editor}` is filled in.

string"Edit conflict with {editor}"

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

Accessibility

  • role="region" with an aria-label naming the editor
  • Message is aria-live="polite"; the compare toggle uses aria-expanded
  • The overwrite confirmation is a labelled group; focus moves to Cancel and Escape closes it

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: Detect conflicts on the server with a version or ETag check, and reject stale writes unless overwrite is explicit.

  • Needs both versions and the editor from your backend; it doesn't detect conflicts itself
  • The diff is word-level on plain text

What it stops

Overwrote a teammate's edit

Also known as

edit conflict · merge conflict · optimistic locking · keep mine · version mismatch · collaboration · cms · diff

Field type

Dependencies

Pairs well with