LockOnMount

<LockOnMount> acquires a record lock when it mounts and releases it on unmount. It renders its children when the lock is held, a loading indicator while locking, and a "locked by" message when the record is already locked by someone else.

Installation

pnpm dlx shadcn@latest add @shadmin/lock-on-mount

Usage

Wrap the form content inside an edit page to prevent concurrent editing:

import { EditLive } from "@/components/realtime";
import { LockOnMount } from "@/components/realtime";
import { SimpleForm, TextInput } from "@/components/admin";
 
export const PostEdit = () => (
  <EditLive>
    <LockOnMount>
      <SimpleForm>
        <TextInput source="title" />
      </SimpleForm>
    </LockOnMount>
  </EditLive>
);

Custom locked state

<LockOnMount
  lockedBy={(lock) => (
    <div className="p-4 text-destructive">
      This record is being edited by {String(lock.identity)}.
    </div>
  )}
>
  <SimpleForm>...</SimpleForm>
</LockOnMount>

Props

PropRequiredTypeDefaultDescription
childrenRequiredReactNodeRendered when the lock is successfully acquired
resourceOptionalstringResourceContextResource name. Falls back to context.
idOptionalIdentifierRecordContext.idRecord ID. Falls back to context.
identityOptionalIdentifieruseGetIdentity()User identity. Falls back to auth provider.
metaOptionalRecord<string, unknown>Forwarded to lock()
loadingOptionalReactNode<Skeleton />Shown while the lock request is in flight
lockedByOptional(lock: Lock) => ReactNode<Alert>Locked by …</Alert>Shown when a LockConflictError is thrown
onLockErrorOptional(error: Error) => voidCalled for any lock error (including conflicts)

Notes

  • Uses useLockOnMount internally — see that hook's page for behaviour details.
  • When resource or id are not in context (e.g. outside a <Edit> or <Show>), pass them explicitly.
  • The lock is released on unmount even if the form was not saved.
  • LockConflictError is detected by instance check; other errors are propagated to onLockError but not rendered by lockedBy.