Presence Lock

Shows who is editing which field and softly locks it in their colour, so two people don't silently overwrite each other's edit.

StopsTwo people editing the same field

Installation

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

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

Usage

presence-lock-usage.tsx
import { PresenceAvatars, PresenceLock, type Collaborator } from "@/components/ui/presence-lock"

<PresenceLock field="price" label="Price per guest" htmlFor="pl-price" people={people}>
  <input id="pl-price" defaultValue="₹650" className={input} />
</PresenceLock>

What it catches

  • Two people editing the same field
  • Edit anyway: warns once before overriding
  • Locks held by people who went idle are released
  • Someone already typing is never locked out

Props

PresenceLock props
PropTypeDefault
field* (required)

The field's key, matched against `Collaborator.field`.

string—
label* (required)

Visible label.

string—
htmlFor

The id of the field's input, so the label is a real `<label>`.

string—
children* (required)

The field itself.

React.ReactNode—
people* (required)

Everyone else on the record.

Collaborator[]—
idleAfter

After this many ms without activity, a person stops locking the field.

number45_000
onEditAnyway

Called when you take the field anyway, e.g. to tell the others.

(field: string) => void—
editingText

Templates: `{names}`, `{label}` and `{when}` are filled in.

string"{names} is editing {label}"
editingManyText

Template when several people edit the field.

string"{names} are editing {label}"
editAnywayLabel

Button text to edit a locked field.

string"Edit anyway"
confirmText

Warning shown before editing anyway.

string"Your change could overwrite theirs."
cancelLabel

Cancel button text.

string"Cancel"
bothText

Template when you and one other are editing.

string"{names} is editing this too. The last save wins."
bothManyText

Template when you and several others are editing.

string"{names} are editing this too. The last save wins."
idleText

Template for people who went idle.

string"{names} was editing {label}, idle for {when}"
freeText

Shown when the field is free.

string"{label} is free to edit now."

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

Accessibility

  • Avatars are a labelled group; images have empty alt with names in titles
  • Joins and leaves are announced in a polite live region
  • A locked field is inert until Edit anyway

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 versioning or merge rules on save so a late write can't silently overwrite another.

  • Soft lock only; your backend must handle conflicting saves
  • Presence comes from your transport; latency can show stale state
  • Idle detection depends on your heartbeats

What it stops

Two people editing the same field

Also known as

presence · collaboration · field lock · liveblocks · multiplayer · realtime · avatars · who's editing

Field type

Dependencies

Pairs well with