> For the complete documentation index, see [llms.txt](https://docs.apryse.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.apryse.com/web/get-started/samples/showcase-demo-annotation-permissions.md).

# Annotations Permissions Showcase Demo Code Sample

Enable customization of user permissions to interact with annotations in the PDF file, completely client-side with three different levels of permissions: administrator, user, and read-only.

{% hint style="info" %}
**Requirements**

*These packages are required to use these features in production. Trial keys have unlimited access to all features*

<a href="/web/get-started/readme.md" class="button primary">Web SDK</a><a href="https://showcase.apryse.com/annotation-permissions" class="button primary">Live demo</a>
{% endhint %}

Enable customization of user permissions to interact with annotations in the PDF file, completely client-side with three different levels of permissions:

* Administrator
* User
* Read-Only

This demo lets you:

* Upload a PDF file and add user permissions
* Add permissions to users as administrator, user, or read-only
* Interact with annotations in the PDF file according to the set permission

**Implementation steps** To add annotations permissions capability to a PDF with WebViewer:

Step 1: Choose your [preferred web stack](/web/get-started/readme.md) Step 2: Add the ES6 JavaScript sample code provided in this guide

Once you generate your license key, it will automatically be included in your sample code below.

{% @apryse-license-key/apryse-license-key platform="WEB\_VIEWER" variant="compact" %}

<pre class="language-js" data-line-numbers><code class="lang-js">
/* ES6 Compliant Syntax */
/* GitHub Copilot v1.0, Claude 3.5 Sonnet, September 1, 2025 */
/* File: index.js */

import WebViewer from '@pdftron/webviewer';

// Annotation Permission section
//
// Code to customize user permissions, completely client-side with 3 
// different levels of permissions: administrator, user, and read-only
//

// Default Document
const defaultDoc = 'https://apryse.s3.us-west-1.amazonaws.com/public/files/samples/WebviewerDemoDoc.pdf';

// Set default user
let currentUser = 'Justin';

// List of users with permissions
let userList = {
    Justin: { permissions: 'administrator', canView: true, hidden: [] },
    Sally: { permissions: 'user', canView: true, hidden: [] },
    Brian: { permissions: 'read-only', canView: true, hidden: [] }
};

// Annotation types that can be toggled for visibility
let toggleableTypes = [];

// Customize UI
const customizeUI = async (instance) => {
    const { Annotations } = instance.Core;
    
    // Load default document
    await instance.Core.documentViewer.loadDocument(defaultDoc, {
        extension: 'pdf',
    });
    instance.UI.setToolbarGroup('toolbarGroup-Annotate', true);

    // Add sticky note, free hand, and highlight to toggleable types
    toggleableTypes = [
        {
            displayName: 'Sticky notes',
            annotationType: Annotations.StickyAnnotation,
        },
        {
            displayName: 'Free hand',
            annotationType: Annotations.FreeHandAnnotation,
        },
        {
            displayName: 'Highlight',
            annotationType: Annotations.TextHighlightAnnotation,
        },
    ];

    // Set user data for mentions in notes tool
    const userData = Object.keys(userList).map((user) => ({
        value: user,
        email: `${user.toLowerCase()}@pdftron.com`,
    }));
    instance.UI.mentions.setUserData(userData);

    // Set default user in the WebViewer
    setUser(instance, currentUser);
};

// Set selected user in the WebViewer
const setUser = (instance, username) => {
    const UI = instance.UI;
    const { annotationManager }= instance.Core;
    annotationManager.setCurrentUser(username);
    const permissions = userList[username].permissions;

    if (permissions === 'administrator') {
        annotationManager.promoteUserToAdmin();
        UI.disableViewOnlyMode();
    } else if (permissions === 'read-only') {
        UI.enableViewOnlyMode();
        annotationManager.demoteUserFromAdmin();
    } else {
        UI.disableViewOnlyMode();
        annotationManager.demoteUserFromAdmin();
    }

    currentUser = username;
    setAnnotationsForUser(instance);
    updateUIControls();
};

// Set annotations for current user
const setAnnotationsForUser = (instance) => {
    const { annotationManager } = instance.Core;

    const { hidden } = userList[currentUser];

    // First get a list of all the types that should be hidden
    const hiddenTypeMap = toggleableTypes.reduce((acc, type) => {
        if (hidden.indexOf(type.displayName) > -1) {
            acc.push(type.annotationType);
        }
        return acc;
    }, []);

    const allAnnots = annotationManager.getAnnotationsList();
    const toShow = [];
    const toHide = [];

    // Generate lists of annotations to show and hide
    allAnnots.forEach((annot) => {
        const isType = hiddenTypeMap.some((type) => annot instanceof type);
        if (isType) {
            toHide.push(annot);
        } else {
            toShow.push(annot);
        }
    });

    // Show and hide annotations
    annotationManager.showAnnotations(toShow);
    annotationManager.hideAnnotations(toHide);
};

// Add user to user list
const addUser = (instance, name, p) => {
    userList = {
        ...userList,
        [name]: { permissions: p, canView: true, hidden: [] },
    };
};

// Toggle annotation type visibility for current user
const toggleAnnotations = (instance, type) => {
    const { displayName } = type;
    const { hidden } = userList[currentUser];
    const idx = hidden.indexOf(displayName);
    const newArray = hidden.slice(0);

    if (idx !== -1) {
        newArray.splice(idx, 1);
    } else {
        newArray.push(displayName);
    }

    userList = {
        ...userList,
        [currentUser]: {
            ...userList[currentUser],
            hidden: newArray
        }
    };

    setAnnotationsForUser(instance);
    updateUIControls();
};

// Check if annotation type is visible for current user
const isChecked = (type) => {
    if (!currentUser) return;
    const { displayName } = type;
    const user = currentUser;
    return userList[user].hidden.indexOf(displayName) === -1;
};


// Helper functions for configuration snippet modal
const perm = () => {
    return currentUser ? userList[currentUser].permissions : null;
}
const hiddenList = () => {
    return currentUser ? userList[currentUser].hidden : [];
};

let text = '';
let annotText = '';

const setText = () => {
    const permission = perm();
    if (permission === 'administrator') {
        text = 'annotationManager.promoteUserToAdmin()';
    } else if (permission === 'read-only') {
        text = 'UI.enableViewOnlyMode()';
    } else {
        text = 'annotationManager.demoteUserFromAdmin();\n  annotationManager.disableReadOnlyMode();';
    }

    return text;
};

const setAnnotText = () => {
    const list = hiddenList();
    if (list.length === 0) {
        annotText = `
  annotationManager.showAnnotations(allAnnots);
      `;
    } else {
        let ifStatement = list.reduce((acc, hidden) => {
            if (hidden === 'Sticky notes') {
                acc += '        annot instanceof Annotations.StickyAnnotation || \n';
            }
            if (hidden === 'Free hand') {
                acc += '        annot instanceof Annotations.FreeHandAnnotation || \n';
            }
            if (hidden === 'Highlight') {
                acc += '        annot instanceof Annotations.TextHighlightAnnotation || \n';
            }

            return acc;
        }, '');

        ifStatement = ifStatement.substring(8, ifStatement.length - 5);

        annotText = `
  const hideList = allAnnots.filter(annot => {
    return ${ifStatement};
    });
  annotationManager.hideAnnotations(hideList);
        `;
    }

    return annotText;
};

// WebViewer section
// 
// This code initializes the WebViewer with the basic settings
// that are found in the default showcase WebViewer
//

const searchParams = new URLSearchParams(window.location.search);
const history = window.history || window.parent.history || window.top.history;
const licenseKey = '<code class="expression">visitor.claims.wvKey || "YOUR_WEBVIEWER_LICENSE_KEY"</code>';
const element = document.getElementById('viewer');

// Initialize WebViewer with the specified settings
WebViewer({
    path: '/lib',
    licenseKey: licenseKey,
    enableFilePicker: true,
}, element).then((instance) => {
    // Enable the measurement toolbar so it appears with all the other tools, and disable Cloudy rectangular tool
    const cloudyTools = [
        instance.Core.Tools.ToolNames.CLOUDY_RECTANGULAR_AREA_MEASUREMENT,
        instance.Core.Tools.ToolNames.CLOUDY_RECTANGULAR_AREA_MEASUREMENT2,
        instance.Core.Tools.ToolNames.CLOUDY_RECTANGULAR_AREA_MEASUREMENT3,
        instance.Core.Tools.ToolNames.CLOUDY_RECTANGULAR_AREA_MEASUREMENT4,
    ];
    instance.UI.enableFeatures([instance.UI.Feature.Measurement, instance.UI.Feature.Initials]);
    instance.UI.disableTools(cloudyTools);

    // Set default toolbar group to Annotate
    instance.UI.setToolbarGroup('toolbarGroup-Annotate');

    // Set default tool on mobile devices to Pan.
    // https://apryse.atlassian.net/browse/WVR-3134
    if (isMobileDevice()) {
        instance.UI.setToolMode(instance.Core.Tools.ToolNames.PAN);
    }

    instance.Core.documentViewer.addEventListener('documentUnloaded', () => {
        if (searchParams.has('file')) {
            searchParams.delete('file');
            history.replaceState(null, '', '?' + searchParams.toString());
        }
    });

    instance.Core.annotationManager.enableAnnotationNumbering();

    instance.UI.NotesPanel.enableAttachmentPreview();

    // Add the demo-specific functionality
    customizeUI(instance).then(() => {
        // Create UI controls after demo is initialized
        createUIControls(instance);
    });
});

// Function to check if the user is on a mobile device
const isMobileDevice = () => {
    return (
        navigator.userAgentData?.mobile ??
        /android|iphone|ipad|ipod|blackberry|iemobile|opera mini|mobile/i.test(
            window.navigator.userAgent
        )
    );
}

// Cleanup function for when the demo is closed or page is unloaded
const cleanup = (instance) => {
    const { documentViewer } = instance.Core;

    if (typeof instance !== 'undefined' &#x26;&#x26; instance.UI) {

        // Reset annotation user to default 'Guest' and promote to admin
        const annotationManager = documentViewer.getAnnotationManager();
        annotationManager.setCurrentUser('Guest');
        annotationManager.promoteUserToAdmin();
        annotationManager.disableReadOnlyMode();

        console.log('Cleaning up compare-files demo');
    }
};

// Register cleanup for page unload
window.addEventListener('beforeunload', () => cleanup());
window.addEventListener('unload', () => cleanup());


// UI section
// 
// Helper code to add controls to the viewer holding the buttons
// This code creates a container for the buttons, styles them, and adds them to the viewer
//

// User selection
const userPageSection = (instance) => {
    // Create a wrapper div for the user section
    const wrapper = document.createElement('div');
    wrapper.className = 'user-page-section';

    // Select User label
    const selectUserLabel = document.createElement('h2');
    selectUserLabel.className = 'header select-user-header';
    selectUserLabel.textContent = 'Select User';

    wrapper.appendChild(selectUserLabel);

    // Users buttons container
    const buttonsContainer = document.createElement('div');
    buttonsContainer.className = 'buttons-container';

    Object.keys(userList).forEach((username) => {
        const button = document.createElement('button');
        button.className = 'btn btn-user';
        button.textContent = `${username} (${userList[username].permissions})`;
        button.onclick = () => {
            setUser(instance, username);
        };

        buttonsContainer.appendChild(button);
    });
    wrapper.appendChild(buttonsContainer);

    // Add User clickable label
    const addUserLabel = document.createElement('label');
    addUserLabel.className = 'add-user-label';
    addUserLabel.textContent = 'Add user';
    addUserLabel.onclick = () => {
        const addUserContainer = document.querySelector('.add-user-container');
        if (addUserContainer.classList.contains('visible')) {
            addUserContainer.classList.remove('visible');
            addUserLabel.textContent = 'Add user';
        } else {
            addUserContainer.classList.add('visible');
            addUserLabel.textContent = 'Close';
        }
    };

    wrapper.appendChild(addUserLabel);

    // Add User container
    const addUserContainer = document.createElement('div');
    addUserContainer.className = 'add-user-container';

    // Add User input field
    const input = document.createElement('input');
    input.type = 'text';
    input.placeholder = 'Username';
    input.className = 'input add-user-input';

    addUserContainer.appendChild(input);

    // Add User permission dropdown
    const permission = document.createElement('select');
    permission.className = 'input add-user-permission';
    permission.options.add(new Option('Administrator', 'administrator'));
    permission.options.add(new Option('User', 'user'));
    permission.options.add(new Option('Read-Only', 'read-only'));

    addUserContainer.appendChild(permission);

    // Add User add button
    const addButton = document.createElement('button');
    addButton.className = 'btn btn-submit-user';
    addButton.textContent = 'Add';
    addButton.onclick = () => {
        // Validate input
        const name = input.value;
        if (name === '') return;
        const p = permission.value;

        // Add user to user list
        addUser(instance, name, p);

        // Add button for new user
        const buttonsContainer = document.querySelector('.buttons-container');
        const button = document.createElement('button');
        button.className = 'btn btn-user';
        button.textContent = `${name} (${p})`;
        button.onclick = () => {
            setUser(instance, name);
        };
        buttonsContainer.appendChild(button);

        // Reset input fields
        input.value = '';
        permission.options.selectedIndex = 0;

        // Close add user section
        addUserLabel.click();
    };

    addUserContainer.appendChild(addButton);

    wrapper.appendChild(addUserContainer);

    return wrapper;
};

// Role permissions description
const rolePermissionsPageSection = () => {
    const wrapper = document.createElement('div');
    wrapper.className = 'role-permissions-section';

    const rolePermissionsLabel = document.createElement('h2');
    rolePermissionsLabel.className = 'header role-permissions-header';
    rolePermissionsLabel.textContent = 'Role Permissions';

    wrapper.appendChild(rolePermissionsLabel);

    const rolePermissionDescription = document.createElement('p');
    rolePermissionDescription.className = 'text role-permission-paragraph';
    const permission = perm();
    if (permission === 'administrator') {
        rolePermissionDescription.innerHTML = '&#x3C;b> Admin: &#x3C;/b> Can add, edit, or remove any annotations created by anyone';
    } else if (permission === 'read-only') {
        rolePermissionDescription.innerHTML = '&#x3C;b> Read-Only: &#x3C;/b> Can only view annotations';
    } else { // user
        rolePermissionDescription.innerHTML = '&#x3C;b> User: &#x3C;/b> Can create, and edit or remove annotations created by themself';
    }

    wrapper.appendChild(rolePermissionDescription);

    return wrapper;
};

// Viewing permissions checkboxes for selected user
const viewingPermissionsPageSection = (instance) => {
    const wrapper = document.createElement('div');
    wrapper.className = 'viewing-permissions-section';

    // Viewing Permissions label
    const viewingPermissionsLabel = document.createElement('label');
    viewingPermissionsLabel.className = 'header viewing-permissions-label';
    viewingPermissionsLabel.textContent = `Set viewing permissions for ` + (currentUser ? currentUser : '...');

    wrapper.appendChild(viewingPermissionsLabel);

    // Viewing Permissions for each annotation type
    const checkboxContainer = document.createElement('div');
    checkboxContainer.className = 'checkbox-container';

    toggleableTypes.forEach((type) => {
        const checkboxRow = document.createElement('div');

        const checkbox = document.createElement('input');
        checkbox.type = 'checkbox';
        checkbox.id = `view-${type.displayName}-checkbox`;
        checkbox.checked = isChecked(type);
        checkbox.onchange = () => {
            toggleAnnotations(instance, type);
        };

        checkboxRow.appendChild(checkbox);

        const label = document.createElement('label');
        label.className = 'text checkbox-label';
        label.ariaLabel = `Toggle ${type.displayName} annotations`;
        label.textContent = `${type.displayName}`;

        checkboxRow.appendChild(label);
        checkboxContainer.appendChild(checkboxRow);
    });
    wrapper.appendChild(checkboxContainer);

    return wrapper;
};


// Helper function to create UI controls
const createUIControls = (instance) => {
    // Create a container for all controls (label, dropdown, and buttons)
    const controlsContainer = document.createElement('div');
    controlsContainer.className = 'controls-container';

    // Add user section
    controlsContainer.appendChild(userPageSection(instance));

    // Add role permissions and viewing permissions sections side by side
    const roleViewingPermissionsContainer = document.createElement('div');
    roleViewingPermissionsContainer.className = 'role-viewing-permissions-container';
    roleViewingPermissionsContainer.appendChild(rolePermissionsPageSection());
    roleViewingPermissionsContainer.appendChild(viewingPermissionsPageSection(instance));
    controlsContainer.appendChild(roleViewingPermissionsContainer);



    element.insertBefore(controlsContainer, element.firstChild);
};

// Helper function to update UI controls
const updateUIControls = () => {
    // Update role permission description
    const rolePermissionDescription = document.querySelector('.role-permission-paragraph');
    if (rolePermissionDescription) {
        const permission = perm();
        if (permission === 'administrator') {
            rolePermissionDescription.innerHTML = '&#x3C;b> Admin: &#x3C;/b> Can add, edit, or remove any annotations created by anyone';
        } else if (permission === 'read-only') {
            rolePermissionDescription.innerHTML = '&#x3C;b> Read-Only: &#x3C;/b> Can only view annotations';
        } else { // user
            rolePermissionDescription.innerHTML = '&#x3C;b> User: &#x3C;/b> Can create, and edit or remove annotations created by themself';
        }
    }

    // Update viewing permissions label
    const viewingPermissionsLabel = document.querySelector('.viewing-permissions-label');
    if (viewingPermissionsLabel) {
        viewingPermissionsLabel.textContent = `Set viewing permissions for ` + (currentUser ? currentUser : '...');
    }

    // Update checkboxes
    toggleableTypes.forEach((type) => {
        const checkbox = document.getElementById(`view-${type.displayName}-checkbox`);
        if (checkbox) {
            checkbox.checked = isChecked(type);
        }
    });

    // Update configuration snippet text
    const codeBlock = document.getElementById('config-snippet-code-block');
    if (codeBlock) {
        codeBlock.textContent = `const wvElement = document.getElementById('viewer');
WebViewer({ ...options }, wvElement)
.then(instance => {
  const { annotationManager } = instance.Core;
  annotationManager.setCurrentUser('${currentUser}');
  ${setText()}
  const allAnnots = annotationManager.getAnnotationsList();
  ${setAnnotText()}
})`;
    }
};
</code></pre>

{% code title="index.css" %}

{% tabs %} {% tab title="CSS" %} {% code lineNumbers="true" %}

```css
/* CSS Standard Compliant Syntax */
/* GitHub Copilot v1.0, Claude 3.5 Sonnet, September 1, 2025 */
/* File: index.css */

/* Base Classes */
.btn {
    display: inline-flex;
    position: relative;
    outline: 2px solid transparent;
    outline-offset: 2px;
    border-radius: 4px;
    font-size: 14px;
    font-weight: 600;
    cursor: pointer;
    transition-property: background-color, border-color, color, fill, stroke, opacity, box-shadow, transform;
    transition-duration: 200ms;
    text-decoration: none;
    line-height: 100%;
    user-select: none;
}

.input {
    outline: 2px solid transparent;
    outline-offset: 2px;
    position: relative;
    transition-property: background-color, border-color, color, fill, stroke, opacity, box-shadow, transform;
    transition-duration: 200ms;
    border-radius: 4px;
    color: #485056;
    border-width: 1px;
    border-style: solid;
    border-color: #cfd4da;
    box-sizing: border-box;
    font-size: 14px;
    height: 25px;
    cursor: pointer;
}

.header {
    font-weight: bold;
    font-size: 14px;
    line-height: 125%;
    color: #334250;
    padding-bottom: 10px;
    display: flex;
    justify-content: space-between;
}

.text {
    font-size: 14px;
    line-height: 20px;
    color: #485056;
    letter-spacing: -0.3px;
}

/* Controls Container */
.controls-container {
    display: flex;
    flex-direction: column;
    gap: 16px;
    margin: 5px 0;
    padding-bottom: 5px;
    border-bottom: 1px solid #e0e0e0;
    background-color: rgba(112, 198, 255, 0.2);
}

/* User Page Section */
.user-page-section {
    margin-bottom: 8px;
}

/* Headers */
.select-user-header,
.role-permissions-header {
    margin: 0;
}

/* Buttons Container */
.buttons-container {
    display: flex;
    flex-direction: row;
    gap: 10px;
}

/* User Buttons */
.btn-user {
    white-space: nowrap;
    width: 100%;
    border: 0;
    padding-inline: 20px;
    padding-top: 12px;
    padding-bottom: 12px;
    height: 40px;
    min-width: 40px;
    background-color: #0056b3;
    color: #ffffff;
    margin-top: 5px;
    max-width: fit-content;
}

.btn-user:hover {
    background-color: #004494;
    transform: translateY(-1px);
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}

/* Add User Label */
.add-user-label {
    font-weight: bold;
    font-size: 14px;
    line-height: 125%;
    color: #0206a8;
    cursor: pointer;
}

/* Add User Container */
.add-user-container {
    display: none; /* Initially hidden */
    gap: 3px;
    align-items: flex-start;
    margin-top: 10px;
}

.add-user-container.visible {
    display: flex;
}

/* Add User Input */
.add-user-input {
    width: 200px;
    appearance: none;
    border-radius: 6px;
    background-color: #ffffff;
    padding-inline-start: 16px;
    padding-inline-end: 16px;
}

/* Add User Permission Dropdown */
.add-user-permission {
    padding-inline-end: 24px;
    padding-bottom: 1px;
    line-height: normal;
    background-color: #f0f0f0;
    margin-left: 3px;
}

/* Submit Button */
.btn-submit-user {
    appearance: none;
    align-items: center;
    justify-content: center;
    padding-top: 12px;
    padding-bottom: 12px;
    height: 25px;
    min-width: 32px;
    background-color: #ffffff;
    color: #0056b3;
    white-space: nowrap;
    padding-inline: 20px;
    border-style: solid;
    border-width: 1px;
    border-color: #0056b3;
    margin-left: 3px;
}

.btn-submit-user:hover {
    background-color: #0056b3;
    color: #ffffff;
}
/* Role Permissions Section */
.role-permissions-section {
    margin-bottom: 8px;
    width: 50%;
}

.role-permission-paragraph {
    margin: 0;
}

/* Viewing Permissions Section */
.viewing-permissions-section {
    display: flex;
    flex-direction: column;
}

/* Checkbox Container */
.checkbox-container {
    display: flex;
    flex-direction: row;
    gap: 8px;
}

.checkbox-container > div {
    display: flex;
    align-items: center;
    gap: 8px;
}

/* Checkboxes */
.checkbox-container input[type="checkbox"] {
    align-items: center;
    justify-content: center;
    width: 20px;
    transition-property: box-shadow;
    transition-duration: 200ms;
    border-width: 2px;
    border-style: solid;
    border-radius: 4px;
    border-color: inherit;
    height: 20px;
    display: inline-flex;
    user-select: none;
    flex-shrink: 0;
}

/* Checkbox Labels */
.checkbox-label {
    align-content: center;
    justify-content: center;
    cursor: pointer;
}

/* Role and Viewing Permissions Container */
.role-viewing-permissions-container {
    display: flex;
    flex-direction: row;
    gap: 20px;
}

/* Responsive Design */
@media (max-width: 768px) {
    .buttons-container {
        flex-direction: column;
        align-items: flex-start;
    }
    
    .btn-user {
        width: 100%;
        max-width: 100%;
        margin: 5px 0;
    }
    
    .add-user-container {
        flex-direction: column;
        align-items: stretch;
    }
    
    .input.add-user-input,
    .input.add-user-permission {
        width: 100%;
        margin-left: 0;
        margin-bottom: 8px;
    }
    
    .btn.btn-submit-user {
        margin-left: 0;
        margin-top: 8px;
    }
    
    .role-viewing-permissions-container {
        flex-direction: column;
        gap: 16px;
    }
}

/* Modal Styles */
.config-modal {
    display: none;
    position: fixed;
    z-index: 1000;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.5);
}

.config-modal-content {
    position: fixed;
    bottom: 0px;
    left: 0px;
    right: 0px;
    max-width: 100vw;
    transform: translateX(0px) translateY(0px) translateZ(0px);
    display: flex;
    flex-direction: column;
    width: 100%;
    outline: transparent solid 2px;
    outline-offset: 2px;
    z-index: 9999999999999;
    max-height: 100vh;
    background-color: #2d2d2d;
    box-shadow:  0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
    pointer-events: auto;
    font-size: 14px;
}

.config-modal-header {
    display: flex;
    flex: 0 1 0%;
    padding-inline-start: 24px;
    padding-inline-end: 24px;
    padding-top: 12px;
    padding-bottom: 0px;
    font-size: 16px;
    font-weight: 600;
    color: #ffffff;
    vertical-align: middle;
}

.btn-copy-config {
    width: 20px;
    height: 20px;
    display: inline-block;
    line-height: 1em;
    flex-shrink: 0;
    color: currentColor;
    vertical-align: middle;
    margin-left: 15px;
    margin-bottom: 2px;
    cursor: pointer;
    background: none;
    border: none;
    font-size: 24px;
}

.btn-close-config {
    background: none;
    border: none;
    outline: transparent solid 2px;
    outline-offset: 2px;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 32px;
    height: 32px;
    border-radius: 6px;
    transition-property: background-color, border-color, color, fill, stroke, opacity, box-shadow, transform;
    transition-duration: 200ms;
    font-size: 24px;
    position: absolute;
    top: 8px;
    right: 12px;
    color: #ffffff;
    cursor: pointer;
}

.btn-copy-config:hover,
.btn-close-config:hover {
    color: #c7d2dd;
}

.config-snippet-code-pre {
    color: #cccccc;
    background: #2d2d2d;
    font-family: monospace;
    font-size: 1em;
    text-align: left;
    white-space: pre;
    word-spacing: normal;
    word-break: normal;
    overflow-wrap: normal;
    line-height: 1.5;
    tab-size: 4;
    hyphens: none;
    padding: 1em;
    margin: 0.5em 0px;
    overflow: auto;
    padding-inline-start: 32px;
    padding-inline-end: 32px;
    padding-top: 0px;
    padding-bottom: 0px;
}

.btn-open-config {
    display: inline-flex;
    appearance: none;
    align-items: center;
    justify-content: center;
    user-select: none;
    position: relative;
    white-space: nowrap;
    vertical-align: middle;
    outline: 2px solid transparent;
    outline-offset: 2px;
    width: 100%;
    line-height: 100%;
    border-radius: 4px;
    font-size: 16px;
    font-weight: 600;
    transition-property: background-color, border-color, color, fill, stroke, opacity, box-shadow, transform;
    transition-duration: 200ms;
    cursor: pointer;
    text-decoration: none;
    padding-inline: 20px 20px;
    padding-top: 12px;
    padding-bottom: 12px;
    height: 40px;
    background-color: #ffffff;
    color: #0056b3;
    border-style: solid;
    border-width: 1px;
    border-color: #0056b3;
    margin-left: 3px;
}

.btn-open-config:hover {
    background-color: #0056b3;
    color: #ffffff;
}
```

[View the full sample on GitHub](https://github.com/ApryseSDK/webviewer-samples/tree/main/showcase-demos-playground)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.apryse.com/web/get-started/samples/showcase-demo-annotation-permissions.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
