Core Configurations

enableSingleEditorMode

Enables single editor mode, allowing only one user to edit the document at a time while others remain in read-only mode.

Params

  • config: (object, optional). Configuration object for controlling single editor mode behavior
    • customMode: (boolean, optional). When true, SDK won’t automatically make HTML elements read-only for viewers. You need to handle this manually with the help of other APIs listed here. (default: false)
    • singleTabEditor: (boolean, optional). When enabled, restricts the editor to edit in only one browser tab at a time, preventing them from making changes across multiple tabs simultaneously (default: true)
const liveStateSyncElement = useLiveStateSyncUtils();

// Basic usage
liveStateSyncElement.enableSingleEditorMode();

// With configuration
liveStateSyncElement.enableSingleEditorMode({ 
    customMode: true,
    singleTabEditor: false 
});

disableSingleEditorMode

Disables single editor mode and returns to normal editing.

const liveStateSyncElement = useLiveStateSyncUtils();
liveStateSyncElement.disableSingleEditorMode();

Define Single Editor Mode Elements

Restrict to specific containers

  • Restrict Single Editor Mode to specific containers.
  • By default Single Editor Mode is enabled at the entire DOM level. You can restrict this feature to only certain HTML containers & their children by using this.
const liveStateSyncElement = useLiveStateSyncUtils();
liveStateSyncElement.singleEditorModeContainerIds(["rightPanel", "editor"]);

Fine tune elements control

Control which elements are controlled by Single Editor Mode.

You must add the data-velt-sync-access-* attributes to native HTML elements (e.g. button, input). It will not work directly on React components.

// Enable sync access on custom elements
return (
    <div data-velt-sync-access="true">
        Controlled by Single Editor Mode
    </div>
);

// Exclude elements from sync access
return (
    <button data-velt-sync-access-disabled="true">
        Not controlled by Single Editor Mode
    </button>
);

enableDefaultSingleEditorUI

  • Control the visibility of the default Single Editor Mode System UI.
  • The default UI shows:
    • Current user’s editor/viewer status
    • Editor access requests
    • Request timeout countdown
    • Request rejection options
  • If you disable the default UI, you’ll need to implement your own UI for these features.
const liveStateSyncElement = useLiveStateSyncUtils();

// Enable default UI (enabled by default)
liveStateSyncElement.enableDefaultSingleEditorUI();

// Disable default UI for custom implementation
liveStateSyncElement.disableDefaultSingleEditorUI();

Timeout Configuration

setEditorAccessTimeout

  • Configure automatic editor access timeout.
  • Default: 5 seconds.
const liveStateSyncElement = useLiveStateSyncUtils();
liveStateSyncElement.setEditorAccessTimeout(15); // in seconds

enableEditorAccessTransferOnTimeOut

  • When editor access timeout is reached, automatically transfer editor access to the next user in the queue.
  • Enabled by default.
const liveStateSyncElement = useLiveStateSyncUtils();
liveStateSyncElement.enableEditorAccessTransferOnTimeOut();

disableEditorAccessTransferOnTimeOut

  • When editor access timeout is reached, do not automatically transfer editor access to the next user in the queue.
  • Enabled by default.
const liveStateSyncElement = useLiveStateSyncUtils();
liveStateSyncElement.disableEditorAccessTransferOnTimeOut();

getEditorAccessTimer

Track the state of editor access request timeout.

Returns

  • EditorAccessTimer object:
    • state ('idle' | 'inProgress' | 'completed')
    • durationLeft (number)
// Using Hooks
const editorAccessTimer = useEditorAccessTimer();

useEffect(() => {
    if (editorAccessTimer?.state === 'completed') {
        // Handle timeout completion
        if (isEditor) {
            acceptEditorAccessRequest();
        } else if (isRequester) {
            setUserAsEditor();
        }
    }
}, [editorAccessTimer]);

return (
    <div>
        Status: {editorAccessTimer?.state}
        Time Left: {editorAccessTimer?.durationLeft}s
    </div>
);


// Using API
const liveStateSyncElement = useLiveStateSyncUtils();
let subscription = liveStateSyncElement.getEditorAccessTimer().subscribe((editorAccessTimer) => {
    console.log('Editor Access Timer:', editorAccessTimer);
});

Auto-Sync Text Elements

  • Enable automatic syncing of text element contents across all users.
  • Supported elements:
    • <input>
    • <textarea>
    • ContentEditable <div>
  • First enable the feature and then define which elements should sync realtime.
const liveStateSyncElement = useLiveStateSyncUtils();

// Enable auto-sync state
liveStateSyncElement.enableAutoSyncState();

// In your JSX
return (
    <textarea id="uniqueId" data-velt-sync-state="true"></textarea>
);

Editor

setUserAsEditor

Sets the current user as the editor, making all other users read-only.

const liveStateSyncElement = useLiveStateSyncUtils();
liveStateSyncElement.setUserAsEditor();

isUserEditor

Get the current user’s editor status.

Returns

  • UserEditorAccess object:
    • isEditor (boolean) - Whether the user is the editor
    • isEditorOnCurrentTab (boolean) - Whether the user is editor on current tab
// Using Hooks
const { isEditor, isEditorOnCurrentTab } = useUserEditorState();

// Using API
const liveStateSyncElement = useLiveStateSyncUtils();
let subscription = liveStateSyncElement.isUserEditor().subscribe((userEditorAccess) => {
    console.log('Is Editor:', userEditorAccess.isEditor);
    console.log('Is Editor on Current Tab:', userEditorAccess.isEditorOnCurrentTab);
});

To unsubscribe from the subscription:

subscription?.unsubscribe()

getEditor

Get information about the current editor.

Returns

  • User object:
    • email (string) - Editor’s email
    • name (string) - Editor’s name
    • photoUrl (string) - Editor’s photo URL
    • userId (string) - Editor’s unique ID
// Using Hooks
const editor = useEditor();

// Using API
const liveStateSyncElement = useLiveStateSyncUtils();
let subscription = liveStateSyncElement.getEditor().subscribe((user) => {
    console.log('Editor:', user);
});

To unsubscribe from the subscription:

subscription?.unsubscribe()

isEditorAccessRequested

Check if any viewer has requested editor access.

Returns

  • null - User is not editor or request was canceled
  • EditorRequest object:
    • requestStatus (string) - ‘requested’ for active requests
    • requestedBy (User) - User object of the requester
// Using Hooks
const editorAccessRequested = useEditorAccessRequestHandler();

// Using API
const liveStateSyncElement = useLiveStateSyncUtils();
let subscription = liveStateSyncElement.isEditorAccessRequested().subscribe((data) => {
    if (data === null) {
        console.log('No active requests or user is not editor');
    } else {
        console.log('Request from:', data.requestedBy.name);
    }
});

To unsubscribe from the subscription:

subscription?.unsubscribe()

acceptEditorAccessRequest

Accept editor access requests.

const liveStateSyncElement = useLiveStateSyncUtils();
liveStateSyncElement.acceptEditorAccessRequest();

rejectEditorAccessRequest

Reject editor access requests.

const liveStateSyncElement = useLiveStateSyncUtils();
liveStateSyncElement.rejectEditorAccessRequest();

editCurrentTab

Make current tab editable when editor has multiple tabs open.

const liveStateSyncElement = useLiveStateSyncUtils();
liveStateSyncElement.editCurrentTab();

Viewer

requestEditorAccess

Request editor access from the current editor.

Returns

  • null - Request is pending
  • true - Request accepted
  • false - Request rejected
const liveStateSyncElement = useLiveStateSyncUtils();
let subscription = liveStateSyncElement.requestEditorAccess().subscribe((status) => {
    if (status === null) console.log('Request pending');
    else if (status === true) console.log('Request accepted');
    else console.log('Request rejected');
});

To unsubscribe from the subscription:

subscription?.unsubscribe()

cancelEditorAccessRequest

Cancel the editor access request.

const liveStateSyncElement = useLiveStateSyncUtils();
liveStateSyncElement.cancelEditorAccessRequest();

resetUserAccess

Reset editor access for all users.

const liveStateSyncElement = useLiveStateSyncUtils();
liveStateSyncElement.resetUserAccess();

Best Practices

  • Use singleTabEditor to prevent confusion when users have multiple tabs open
  • Add IDs to HTML elements with sync attributes for more robust syncing
  • Only apply sync attributes to native HTML elements, not framework components