> 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-complex-generation.md).

# Conditional Content for Document Generation Showcase Demo Code Sample

Generate complex documents using conditionals denoted by {{ifcond}} and {{endif}} clauses.

{% 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://apryse.com/capabilities#Template" class="button primary">Package: Template</a><a href="https://showcase.apryse.com/complex-generation" class="button primary">Live demo</a>
{% endhint %}

Generate documents using conditionals denoted by `{{if cond}}` and `{{endif}}` clauses. Conditionals can be helpful when content in the document should only be included in certain cases.

This demo allows you to:

* Generate a PDF with conditional clauses
* Customize contents
* Download updated PDF

### **Implementation steps**

To add document generation capability using conditional clauses 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, July 31, 2025
// File: index.js

import WebViewer from '@pdftron/webviewer';

// Document Generation using Conditionals with JSON Data &#x26; JS
// 
// This code demonstrates how to fill a DOCX template with JSON data, this
// template includes conditional logic to display different content based 
// on the data provided.
// This can be seen by the red PAST DUE marking on the invoice template that
// is wrapped by the {{if condition}} and {{endif}} tags.
//

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

// JSON data for filling the template
const sampleData = {
    'bill_to_name': 'Joey Hansen',
    'past_due': true,
    'pay_by_date': '20-03-2022',
    'ship_to_name': 'Kathryn Hoover',
    'total_due': '250.00',
    'total_owing': '150.00',
    'total_paid': '100.00',
};

// Load the default template document
const customizeUI = async (instance) => {
    // Load DOCX template
    await instance.Core.documentViewer.loadDocument(defaultDoc, {
        extension: 'docx',
    });
};

// Apply JSON data to the PDF
const fillTemplate = async (instance) => {
    await instance.Core.documentViewer.getDocument().applyTemplateValues(sampleData);
};

// 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');

WebViewer({
    path: '/lib',
    licenseKey: licenseKey,
}, 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 (
        /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|ipad|iris|kindle|Android|Silk|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(
            window.navigator.userAgent
        ) ||
        /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw-(n|u)|c55\/|capi|ccwa|cdm-|cell|chtm|cldc|cmd-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc-s|devi|dica|dmob|do(c|p)o|ds(12|-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(-|_)|g1 u|g560|gene|gf-5|g-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd-(m|p|t)|hei-|hi(pt|ta)|hp( i|ip)|hs-c|ht(c(-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i-(20|go|ma)|i230|iac( |-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|-[a-w])|libw|lynx|m1-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|-([1-8]|c))|phil|pire|pl(ay|uc)|pn-2|po(ck|rt|se)|prox|psio|pt-g|qa-a|qc(07|12|21|32|60|-[2-7]|i-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h-|oo|p-)|sdk\/|se(c(-|0|1)|47|mc|nd|ri)|sgh-|shar|sie(-|m)|sk-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h-|v-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl-|tdg-|tel(i|m)|tim-|t-mo|to(pl|sh)|ts(70|m-|m3|m5)|tx-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas-|your|zeto|zte-/i.test(
            window.navigator.userAgent.substring(0, 4)
        )
    );
}

// Cleanup function for when the demo is closed or page is unloaded
const cleanup = (instance) => {
    if (typeof instance !== 'undefined' &#x26;&#x26; instance.UI) {
        // Clean up any resources if needed
        console.log('Cleaning up complex-generation 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
//

// Text input field
const createTextInput = (fieldName, value) => {
    const container = document.createElement('div');
    container.className = 'input-container';

    const label = document.createElement('label');
    label.textContent = fieldName;
    container.appendChild(label);

    const input = document.createElement('input');
    input.name = fieldName.toLowerCase().replace(/ /g, '_');
    input.type = 'text';
    input.value = value || '';
    input.className = 'text-input';
    input.onchange = (e) => {
        sampleData[input.name] = e.target.value;
    };
    container.appendChild(input);

    return container;
};

// Checkbox field
const createCheckbox = (fieldName, checked) => {
    const container = document.createElement('div');
    container.className = 'checkbox-container';

    // Create label for the checkbox
    const label = document.createElement('label');
    label.textContent = fieldName;
    container.appendChild(label);

    const checkbox = document.createElement('input');
    checkbox.name = fieldName.toLowerCase().replace(/ /g, '_');
    checkbox.type = 'checkbox';
    checkbox.checked = checked || false;
    checkbox.className = 'checkbox-input';
    checkbox.onchange = (e) => {
        sampleData[checkbox.name] = e.target.checked;
    };
    container.appendChild(checkbox);

    return container;
};

// Fill Template Button
const fillTemplateButton = (instance) => {
    const button = document.createElement('button');
    button.className = 'btn';
    button.textContent = 'Fill Template';
    button.onclick = () => {
        fillTemplate(instance, sampleData);
    };
    return button;
};

// Reset Document Button
const resetDocumentButton = (instance) => {
    const button = document.createElement('button');
    button.className = 'btn';
    button.textContent = 'Reset Document';
    button.onclick = async () => {
        await instance.Core.documentViewer.loadDocument(defaultDoc, {
            extension: 'docx',
        });

        // Reset Sample Data
        sampleData.bill_to_name = 'Joey Hansen';
        sampleData.past_due = true;
        sampleData.pay_by_date = '20-03-2022';
        sampleData.ship_to_name = 'Kathryn Hoover';
        sampleData.total_due = '250.00';
        sampleData.total_owing = '150.00';
        sampleData.total_paid = '100.00';

        // Reset all text inputs and checkboxes
        const textInputs = document.querySelectorAll('.text-input');
        textInputs.forEach((input) => {
            input.value = sampleData[input.name] || '';
        });
        const checkboxes = document.querySelectorAll('.checkbox-input');
        checkboxes.forEach((checkbox) => {
            checkbox.checked = sampleData[checkbox.name] || false;
        });
    };

    return button;
};

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

    // Buttons Container
    const buttonsContainer = document.createElement('div');
    buttonsContainer.className = 'buttons-container';
    buttonsContainer.appendChild(fillTemplateButton(instance));
    buttonsContainer.appendChild(resetDocumentButton(instance));
    controlsContainer.appendChild(buttonsContainer);

    // Create a container for the text inputs
    const textInputsContainer = document.createElement('div');
    textInputsContainer.className = 'text-inputs-container';

    // bill_to_name field
    const billToNameInput = createTextInput('Bill To name', sampleData.bill_to_name);
    textInputsContainer.appendChild(billToNameInput);

    // past_due field
    const pastDueCheckbox = createCheckbox('Past Due', sampleData.past_due);
    textInputsContainer.appendChild(pastDueCheckbox);

    // pay_by_date field
    const payByDateInput = createTextInput('Pay By Date', sampleData.pay_by_date);
    textInputsContainer.appendChild(payByDateInput);

    // ship_to_name field
    const shipToNameInput = createTextInput('Ship To Name', sampleData.ship_to_name);
    textInputsContainer.appendChild(shipToNameInput);

    // total_due field
    const totalDueInput = createTextInput('Total Due', sampleData.total_due);
    textInputsContainer.appendChild(totalDueInput);

    // total_owing field
    const totalOwingInput = createTextInput('Total Owing', sampleData.total_owing);
    textInputsContainer.appendChild(totalOwingInput);

    // total_paid field
    const totalPaidInput = createTextInput('Total Paid', sampleData.total_paid);
    textInputsContainer.appendChild(totalPaidInput);

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


</code></pre>


---

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