> ## Documentation Index
> Fetch the complete documentation index at: https://docs.velt.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Customize Behavior

## 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`)

<Tabs>
  <Tab title="React / Next.js">
    ```jsx theme={null}
    const liveStateSyncElement = useLiveStateSyncUtils();

    // Basic usage
    liveStateSyncElement.enableSingleEditorMode();

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

  <Tab title="Other Frameworks">
    ```jsx theme={null}
    // Get LiveStateSyncElement from Velt Client
    const liveStateSyncElement = Velt.getLiveStateSyncElement();

    // Basic usage
    liveStateSyncElement.enableSingleEditorMode();

    // With configuration
    liveStateSyncElement.enableSingleEditorMode({
        customMode: true,
        singleTabEditor: false
    });
    ```
  </Tab>
</Tabs>

## disableSingleEditorMode

Disables single editor mode and returns to normal editing.

<Tabs>
  <Tab title="React / Next.js">
    ```jsx theme={null}
    const liveStateSyncElement = useLiveStateSyncUtils();
    liveStateSyncElement.disableSingleEditorMode();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx theme={null}
    const liveStateSyncElement = Velt.getLiveStateSyncElement();
    liveStateSyncElement.disableSingleEditorMode();
    ```
  </Tab>
</Tabs>

## 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.

<Tabs>
  <Tab title="React / Next.js">
    ```jsx theme={null}
    const liveStateSyncElement = useLiveStateSyncUtils();
    liveStateSyncElement.singleEditorModeContainerIds(["rightPanel", "editor"]);
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx theme={null}
    const liveStateSyncElement = Velt.getLiveStateSyncElement();
    liveStateSyncElement.singleEditorModeContainerIds(["rightPanel", "editor"]);
    ```
  </Tab>
</Tabs>

### Fine tune elements control

Control which elements are controlled by Single Editor Mode.

<Warning>
  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.
</Warning>

<Tabs>
  <Tab title="React / Next.js">
    ```jsx theme={null}
    // 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>
    );
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```html theme={null}
    <!-- Enable sync access on custom elements -->
    <div data-velt-sync-access="true">
        Controlled by Single Editor Mode
    </div>

    <!-- Exclude elements from sync access -->
    <button data-velt-sync-access-disabled="true">
        Not controlled by Single Editor Mode
    </button>
    ```
  </Tab>
</Tabs>

## Timeout Configuration

### setEditorAccessTimeout

* Configure automatic editor access timeout.
* Default: `5 seconds`.

<Tabs>
  <Tab title="React / Next.js">
    ```jsx theme={null}
    const liveStateSyncElement = useLiveStateSyncUtils();
    liveStateSyncElement.setEditorAccessTimeout(15); // in seconds
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx theme={null}
    const liveStateSyncElement = Velt.getLiveStateSyncElement();
    liveStateSyncElement.setEditorAccessTimeout(15); // in seconds
    ```
  </Tab>
</Tabs>

### enableEditorAccessTransferOnTimeOut

* When editor access timeout is reached, automatically transfer editor access to the next user in the queue.
* Enabled by default.

<Tabs>
  <Tab title="React / Next.js">
    ```jsx theme={null}
    const liveStateSyncElement = useLiveStateSyncUtils();
    liveStateSyncElement.enableEditorAccessTransferOnTimeOut();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx theme={null}
    const liveStateSyncElement = Velt.getLiveStateSyncElement();
    liveStateSyncElement.enableEditorAccessTransferOnTimeOut();
    ```
  </Tab>
</Tabs>

### disableEditorAccessTransferOnTimeOut

* When editor access timeout is reached, do not automatically transfer editor access to the next user in the queue.
* Enabled by default.

<Tabs>
  <Tab title="React / Next.js">
    ```jsx theme={null}
    const liveStateSyncElement = useLiveStateSyncUtils();
    liveStateSyncElement.disableEditorAccessTransferOnTimeOut();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx theme={null}
    const liveStateSyncElement = Velt.getLiveStateSyncElement();
    liveStateSyncElement.disableEditorAccessTransferOnTimeOut();
    ```
  </Tab>
</Tabs>

### getEditorAccessTimer

Track the state of editor access request timeout.

**Returns**

* `EditorAccessTimer` object:
  * `state` (`'idle'` | `'inProgress'` | `'completed'`)
  * `durationLeft` (`number`)

<Tabs>
  <Tab title="React / Next.js">
    ```jsx theme={null}
    // 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);
    });

    ```
  </Tab>
</Tabs>

## 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.

<Tabs>
  <Tab title="React / Next.js">
    ```jsx theme={null}
    const liveStateSyncElement = useLiveStateSyncUtils();

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

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

  <Tab title="Other Frameworks">
    ```html theme={null}
    <script>
    const liveStateSyncElement = Velt.getLiveStateSyncElement();
    liveStateSyncElement.enableAutoSyncState();
    </script>

    <body>
        <!-- Enable auto-sync on text elements -->
        <textarea id="uniqueId" data-velt-sync-state="true"></textarea>
    </body>
    ```
  </Tab>
</Tabs>

## Editor

### setUserAsEditor

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

<Tabs>
  <Tab title="React / Next.js">
    ```jsx theme={null}
    const liveStateSyncElement = useLiveStateSyncUtils();
    liveStateSyncElement.setUserAsEditor();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx theme={null}
    const liveStateSyncElement = Velt.getLiveStateSyncElement();
    liveStateSyncElement.setUserAsEditor();
    ```
  </Tab>
</Tabs>

#### Error handling

`setUserAsEditor` includes validations to prevent assigning an editor when one already exists. It returns a promise that resolves to an optional error object.

<Tabs>
  <Tab title="React / Next.js">
    ```ts theme={null}
    export interface SetUserAsEditorResponse {
      error?: ErrorEvent;
    }

    export type ErrorEvent = {
      error?: string;
      code: string;
      message?: string;
      source?: string;
    };

    // Usage
    const liveStateSyncElement = useLiveStateSyncUtils();
    const result = await liveStateSyncElement.setUserAsEditor();
    if (result?.error) {
      if (result.error.code === 'same_user_editor_current_tab') {
        // Same user already editor in current tab
      } else if (result.error.code === 'same_user_editor_different_tab') {
        // Same user already editor in different tab
      } else if (result.error.code === 'another_user_editor') {
        // Another user already editor
      }
    }
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```js theme={null}
    const liveStateSyncElement = Velt.getLiveStateSyncElement();
    const result = await liveStateSyncElement.setUserAsEditor();
    if (result && result.error) {
      if (result.error.code === 'same_user_editor_current_tab') {
        // Same user already editor in current tab
      } else if (result.error.code === 'same_user_editor_different_tab') {
        // Same user already editor in different tab
      } else if (result.error.code === 'another_user_editor') {
        // Another user already editor
      }
    }
    ```
  </Tab>
</Tabs>

Possible error values:

```ts theme={null}
{
  code: 'same_user_editor_current_tab',
  message: 'Same user is already editor in current tab.',
  source: 'setUserAsEditor',
}
{
  code: 'same_user_editor_different_tab',
  message: 'Same user is already editor in different tab.',
  source: 'setUserAsEditor',
}
{
  code: 'another_user_editor',
  message: 'Another user is already editor.',
  source: 'setUserAsEditor',
}
```

### isUserEditor

* Get the current user's editor status.

**Returns**

* `null`: When the state is not available yet.
* `undefined`: When there are no current editors available in single editor mode.
* `UserEditorAccess`: When there is at least one editor available in single editor mode.
  * `isEditor` (`boolean`) - Whether the user is the editor
  * `isEditorOnCurrentTab` (`boolean`) - Whether the user is editor on current tab

<Tabs>
  <Tab title="React / Next.js">
    ```jsx theme={null}
    // 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:

    ```jsx theme={null}
    subscription?.unsubscribe()
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx theme={null}
    const liveStateSyncElement = Velt.getLiveStateSyncElement();
    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()
    ```
  </Tab>
</Tabs>

### 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

<Tabs>
  <Tab title="React / Next.js">
    ```jsx theme={null}
    // 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:

    ```jsx theme={null}
    subscription?.unsubscribe()
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx theme={null}
    const liveStateSyncElement = Velt.getLiveStateSyncElement();
    let subscription = liveStateSyncElement.getEditor().subscribe((user) => {
        console.log('Editor:', user);
    });

    // To unsubscribe from the subscription:
    subscription?.unsubscribe()
    ```
  </Tab>
</Tabs>

### 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

<Tabs>
  <Tab title="React / Next.js">
    ```jsx theme={null}
    // 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:

    ```jsx theme={null}
    subscription?.unsubscribe()
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx theme={null}
    const liveStateSyncElement = Velt.getLiveStateSyncElement();
    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()
    ```
  </Tab>
</Tabs>

### acceptEditorAccessRequest

Accept editor access requests.

<Tabs>
  <Tab title="React / Next.js">
    ```jsx theme={null}
    const liveStateSyncElement = useLiveStateSyncUtils();
    liveStateSyncElement.acceptEditorAccessRequest();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx theme={null}
    const liveStateSyncElement = Velt.getLiveStateSyncElement();
    liveStateSyncElement.acceptEditorAccessRequest();
    ```
  </Tab>
</Tabs>

### rejectEditorAccessRequest

Reject editor access requests.

<Tabs>
  <Tab title="React / Next.js">
    ```jsx theme={null}
    const liveStateSyncElement = useLiveStateSyncUtils();
    liveStateSyncElement.rejectEditorAccessRequest();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx theme={null}
    const liveStateSyncElement = Velt.getLiveStateSyncElement();
    liveStateSyncElement.rejectEditorAccessRequest();
    ```
  </Tab>
</Tabs>

### editCurrentTab

Make current tab editable when editor has multiple tabs open.

<Tabs>
  <Tab title="React / Next.js">
    ```jsx theme={null}
    const liveStateSyncElement = useLiveStateSyncUtils();
    liveStateSyncElement.editCurrentTab();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx theme={null}
    const liveStateSyncElement = Velt.getLiveStateSyncElement();
    liveStateSyncElement.editCurrentTab();
    ```
  </Tab>
</Tabs>

## Viewer

### requestEditorAccess

Request editor access from the current editor.

**Returns**

* `null` - Request is pending
* `true` - Request accepted
* `false` - Request rejected

<Tabs>
  <Tab title="React / Next.js">
    ```jsx theme={null}
    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:

    ```jsx theme={null}
    subscription?.unsubscribe()
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx theme={null}
    const liveStateSyncElement = Velt.getLiveStateSyncElement();
    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()
    ```
  </Tab>
</Tabs>

### cancelEditorAccessRequest

Cancel the editor access request.

<Tabs>
  <Tab title="React / Next.js">
    ```jsx theme={null}
    const liveStateSyncElement = useLiveStateSyncUtils();
    liveStateSyncElement.cancelEditorAccessRequest();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx theme={null}
    const liveStateSyncElement = Velt.getLiveStateSyncElement();
    liveStateSyncElement.cancelEditorAccessRequest();
    ```
  </Tab>
</Tabs>

## Heartbeat

The heartbeat mechanism provides more reliable presence detection in single editor mode scenarios. This feature is enabled by default when single editor mode is enabled.

<Note>
  If you want to disable heartbeat functionality, you must disable it before enabling single editor mode.
</Note>

### [enableHeartbeat](/api-reference/sdk/api/api-methods#enableheartbeat)

Enables/Disables the heartbeat mechanism for Single Editor Mode presence detection.

Default: `enabled`

<Tabs>
  <Tab title="React / Next.js">
    ```jsx theme={null}
    const liveStateSyncElement = useLiveStateSyncUtils();
    liveStateSyncElement.enableHeartbeat();
    liveStateSyncElement.disableHeartbeat();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx theme={null}
    const liveStateSyncElement = Velt.getLiveStateSyncElement();
    liveStateSyncElement.enableHeartbeat();
    liveStateSyncElement.disableHeartbeat();
    ```
  </Tab>
</Tabs>

## Presence Heartbeat

### updateUserPresence

Send a lightweight heartbeat from your host app to Velt. Velt will use that as a fallback in rare edge cases if it fails to detect multi‑tab/device presence. Most apps don't need this; use only if you see ambiguity in who's the active editor.

<Tabs>
  <Tab title="React / Next.js">
    ```ts theme={null}
    export interface LiveStateSingleEditorExternalUserPresence {
      /** True if the same user is present on a different tab. */
      sameUserPresentOnTab?: boolean;
      /** True if a different user is present on a different tab. */
      differentUserPresentOnTab?: boolean;
      /** User IDs of users present on a different tab. */
      userIds?: string[];
    }

    const liveStateSyncElement = useLiveStateSyncUtils();
    liveStateSyncElement.updateUserPresence({
      sameUserPresentOnTab: false,
      differentUserPresentOnTab: true,
      userIds: ['user-2']
    });
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```ts theme={null}
    export interface LiveStateSingleEditorExternalUserPresence {
      /** True if the same user is present on a different tab. */
      sameUserPresentOnTab?: boolean;
      /** True if a different user is present on a different tab. */
      differentUserPresentOnTab?: boolean;
      /** User IDs of users present on different tabs. */
      userIds?: string[];
    }
    ```

    ```js theme={null}
    // API method
    const liveStateSyncElement = Velt.getLiveStateSyncElement();

    const userPresenceObject = {
      sameUserPresentOnTab: false,
      differentUserPresentOnTab: true,
      userIds: ['user-2']
    };

    liveStateSyncElement.updateUserPresence(userPresenceObject);
    ```
  </Tab>
</Tabs>

### resetUserAccess

Reset editor access for all users.

<Tabs>
  <Tab title="React / Next.js">
    ```jsx theme={null}
    const liveStateSyncElement = useLiveStateSyncUtils();
    liveStateSyncElement.resetUserAccess();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx theme={null}
    const liveStateSyncElement = Velt.getLiveStateSyncElement();
    liveStateSyncElement.resetUserAccess();
    ```
  </Tab>
</Tabs>

## UI

### 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.

<Tabs>
  <Tab title="React / Next.js">
    ```jsx theme={null}
    const liveStateSyncElement = useLiveStateSyncUtils();

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

    // Disable default UI for custom implementation
    liveStateSyncElement.disableDefaultSingleEditorUI();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx theme={null}
    const liveStateSyncElement = Velt.getLiveStateSyncElement();

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

    // Disable default UI for custom implementation
    liveStateSyncElement.disableDefaultSingleEditorUI();
    ```
  </Tab>
</Tabs>

### Embed Single Editor Mode Panel

* Embed the Single Editor Mode Panel into your UI.

<Tabs>
  <Tab title="React / Next.js">
    ```jsx theme={null}
    <VeltSingleEditorModePanel shadowDom={false} darkMode={true} variant="custom-ui" />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```html theme={null}
    <velt-single-editor-mode-panel shadow-dom="false" dark-mode="true" variant="custom-ui"></velt-single-editor-mode-panel>
    ```
  </Tab>
</Tabs>

## Event Subscription

### on

Subscribe to Single Editor Mode Events. Here is the list of events you can subscribe to and the event objects you will receive.

| Category          | Event Type                     | Description                                                                                     | Event Object                                                                   |
| ----------------- | ------------------------------ | ----------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ |
| Editor            | `accessRequested`              | When a user requests editor access. Editor will get this event.                                 | [AccessRequestEvent](/api-reference/sdk/models/data-models#accessrequestevent) |
| Editor            | `accessRequestCanceled`        | When a user cancels their request for editor access. Editor will get this event.                | [AccessRequestEvent](/api-reference/sdk/models/data-models#accessrequestevent) |
| Viewer            | `accessAccepted`               | When a user's request for editor access is accepted. Requesting Viewer will get this event.     | [AccessRequestEvent](/api-reference/sdk/models/data-models#accessrequestevent) |
| Viewer            | `accessRejected`               | When a user's request for editor access is rejected. Requesting Viewer will get this event.     | [AccessRequestEvent](/api-reference/sdk/models/data-models#accessrequestevent) |
| Access Assignment | `editorAssigned`               | When a user is assigned as the editor.                                                          | [SEMEvent](/api-reference/sdk/models/data-models#semevent)                     |
| Access Assignment | `viewerAssigned`               | When a user is assigned as a viewer.                                                            | [SEMEvent](/api-reference/sdk/models/data-models#semevent)                     |
| Editor            | `editorOnDifferentTabDetected` | When the editor opens the same document in a different browser tab. Editor will get this event. | [SEMEvent](/api-reference/sdk/models/data-models#semevent)                     |

<Tabs>
  <Tab title="React / Next.js">
    **Using Hooks:**

    ```jsx theme={null}
    // Replace "EVENT_TYPE" with an actual event string. eg: "accessRequested".
    const eventData = useLiveStateSyncEventCallback("EVENT_TYPE"); 

    useEffect(() => {
      if (eventData) { 
        console.log("EVENT_TYPE data: ", eventData);
      }
    }, [eventData]);
    ```

    **Using API:**

    ```jsx theme={null}
    const liveStateSyncElement = useLiveStateSyncUtils();
    // Replace "EVENT_TYPE" with an actual event string. eg: "accessRequested".
    liveStateSyncElement.on("EVENT_TYPE").subscribe((eventData) => {
      console.log("EVENT_TYPE data: ", eventData);
    });
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```javascript theme={null}
    const liveStateSyncElement = Velt.getLiveStateSyncElement();
    // Replace "EVENT_TYPE" with an actual event string. eg: "accessRequested".
    liveStateSyncElement.on("EVENT_TYPE").subscribe((eventData) => {
      console.log("EVENT_TYPE data: ", eventData);
    });
    ```
  </Tab>
</Tabs>

## 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
