Declarative API Reference

The Declarative API lets you link HTML elements to NExS app cells using CSS classes and data attributes—no JavaScript required.

Overview

Add specific class names and a data-nexs-cell-addr attribute to HTML elements to create automatic two-way binding with your NExS app cells.

Input Elements

Class: nexs__input

Links an input element to an editable cell. Changes flow both directions:

  • User edits the HTML input → value sent to NExS cell
  • NExS cell changes → HTML input updates

Supported Input Types

Text Input

<input type="text"
       class="nexs__input"
       data-nexs-cell-addr="B5">

Checkbox

<input type="checkbox"
       class="nexs__input"
       data-nexs-cell-addr="C3">
  • Checked = sends 1 to cell
  • Unchecked = sends 0 to cell

Radio Buttons

<input type="radio" name="plan" class="nexs__input"
       data-nexs-cell-addr="B8" value="Basic"> Basic

<input type="radio" name="plan" class="nexs__input"
       data-nexs-cell-addr="B8" value="Premium"> Premium

<input type="radio" name="plan" class="nexs__input"
       data-nexs-cell-addr="B8" value="Enterprise"> Enterprise

All radio buttons in a group share the same data-nexs-cell-addr. The selected button’s value is sent to the cell.

Select (Dropdown)

<select class="nexs__input" data-nexs-cell-addr="D2">
  <option value="Option A">Option A</option>
  <option value="Option B">Option B</option>
  <option value="Option C">Option C</option>
</select>

The selected option’s value is sent to the cell.

Output Elements

Class: nexs__output_formatted

Displays the cell’s formatted value (as shown in Excel).

<span class="nexs__output_formatted"
      data-nexs-cell-addr="B10"></span>

If cell B10 contains 1234.56 formatted as currency, displays: $1,234.56

Class: nexs__output_raw

Displays the cell’s raw value (unformatted).

<span class="nexs__output_raw"
      data-nexs-cell-addr="B10"></span>

If cell B10 contains 1234.56 formatted as currency, displays: 1234.56

Comparison

Cell Value Format nexs__output_formatted nexs__output_raw
1234.56 Currency $1,234.56 1234.56
0.15 Percentage 15% 0.15
44927 Date 1/15/2023 44927
Hello Text Hello Hello

The _raw and _formatted classes only differ for numeric values. Text cells display the same in both.

View Selector

Class: nexs__viewselect

Creates a dropdown that switches between views.

<select class="nexs__viewselect"></select>

The dropdown automatically populates with your app’s view names.

Multiple Apps

For pages with multiple embedded apps, specify which app:

<!-- View selector for second app (index 1) -->
<select class="nexs__viewselect" data-nexs-app="1"></select>

<!-- View selector for app named "My App" -->
<select class="nexs__viewselect" data-nexs-app="My App"></select>

Cell Address Syntax

The data-nexs-cell-addr attribute uses the extended cell reference syntax: [appRef]viewRef!cellRef

Components

Component Description Examples
appRef App name or index [My App], [0], [1]
viewRef View name or index Dashboard, 0, 1
cellRef Cell address or name B7, Input_1

Default Values

  • If appRef is omitted, defaults to first app ([0])
  • If viewRef is omitted, defaults to first view (0)

Examples

Address Meaning
B5 Cell B5 on first view of first app
Dashboard!B5 Cell B5 on “Dashboard” view of first app
[My App]Dashboard!B5 Cell B5 on “Dashboard” view of “My App”
[1]B5 Cell B5 on first view of second app
[0]2!B5 Cell B5 on third view of first app
Input_1 Named cell “Input_1” on first view of first app
[My App]Settings!Config Named cell “Config” on “Settings” view of “My App”

Complete Example

This mortgage calculator is a custom page built entirely with the Declarative API. It runs against a published NExS app built from a mortgage analysis spreadsheet. Download the spreadsheet to see how it works, or open the Mortgage Calculator app in a new window to compare it with the original spreadsheet view.

The spreadsheet’s inputs are in Sheet1!C7:C19, and its NExS.app worksheet makes them editable:

A B C
1 app Mortgage Calculator
2 view Sheet1!B2:K23
3 name Main
4 input C7:C10
5 input C15:C19
6 end

The custom page binds to these cells:

Cell Contents Bound to
C7 Mortgage term (years) Radio buttons, one shared cell
C8 Rate Text input
C9 Purchase price Text input
C10 Down payment Text input
C15 Additional principal (monthly) Text input
C16 Marginal tax bracket Select
C17 Annual appreciation Text input
C18 Insurance (annual) Text input
C19 Property tax rate Text input
C11, C12 Loan amount, monthly payment nexs__output_formatted
F17:K17 Cash out, tax savings, net cost, loan balance, property value, and equity after 10 years nexs__output_formatted

On their own, nexs__input text inputs show the cell’s raw value, so the rate would appear as 0.04 and the purchase price as 500000. A short nexsappupdated listener replaces them with the cell’s formatted text (4.000%, $500,000) after every update. It skips the input the user is typing in. Formatted values are safe to send back, because text inputs accept the same entries as the spreadsheet cell. Type rates with a percent sign (6.5%), because a plain 6.5 would be read as 650%.

Try It

Mortgage Calculator

Loan Term (years)
Monthly Payment
on a loan of

After 10 Years

Cash out
Tax savings
Net cost
Loan balance
Property value
Equity

The Code

<!DOCTYPE html>
<html lang="en">
<head>
  <title>Mortgage Calculator</title>
  <style>
    .calculator {
      font-family: Arial, sans-serif;
      max-width: 560px;
      margin: 20px auto;
      padding: 24px;
      border: 1px solid #ddd;
      border-radius: 8px;
    }
    .fields {
      display: grid;
      grid-template-columns: 1fr 1fr;
      gap: 0 16px;
    }
    .field {
      margin-bottom: 15px;
    }
    .field-label {
      display: block;
      font-weight: bold;
      margin-bottom: 5px;
    }
    .field input[type="text"], .field select {
      width: 100%;
      padding: 8px;
      font-size: 16px;
      box-sizing: border-box;
    }
    .radio-row {
      display: flex;
      gap: 16px;
      padding: 8px 0;
    }
    .result {
      background: #f0f8ff;
      padding: 15px;
      border-radius: 4px;
      text-align: center;
    }
    .result .amount {
      font-size: 32px;
      font-weight: bold;
      color: #2a7;
    }
    .summary {
      margin-top: 15px;
      display: grid;
      grid-template-columns: 1fr 1fr;
      gap: 8px 16px;
    }
    .summary h4 {
      grid-column: 1 / -1;
      margin: 0;
    }
    .summary div {
      display: flex;
      justify-content: space-between;
      border-bottom: 1px solid #eee;
    }
  </style>
</head>
<body>

<div class="calculator">
  <h2>Mortgage Calculator</h2>

  <div class="fields">
    <!-- Text inputs -->
    <div class="field">
      <label class="field-label" for="price">Purchase Price</label>
      <input type="text" id="price"
             class="nexs__input"
             data-nexs-cell-addr="C9"
             placeholder="$500,000">
    </div>

    <div class="field">
      <label class="field-label" for="down">Down Payment</label>
      <input type="text" id="down"
             class="nexs__input"
             data-nexs-cell-addr="C10"
             placeholder="$200,000">
    </div>

    <div class="field">
      <label class="field-label" for="rate">Interest Rate (e.g. 6.5%)</label>
      <input type="text" id="rate"
             class="nexs__input"
             data-nexs-cell-addr="C8"
             placeholder="6.5%">
    </div>

    <div class="field">
      <label class="field-label" for="extra">Extra Principal / Month</label>
      <input type="text" id="extra"
             class="nexs__input"
             data-nexs-cell-addr="C15"
             placeholder="$0">
    </div>

    <!-- Radio buttons: all share cell C7, and the selected value is sent -->
    <div class="field">
      <span class="field-label">Loan Term (years)</span>
      <div class="radio-row">
        <label>
          <input type="radio" name="term" class="nexs__input"
                 data-nexs-cell-addr="C7" value="15"> 15
        </label>
        <label>
          <input type="radio" name="term" class="nexs__input"
                 data-nexs-cell-addr="C7" value="20"> 20
        </label>
        <label>
          <input type="radio" name="term" class="nexs__input"
                 data-nexs-cell-addr="C7" value="30" checked> 30
        </label>
      </div>
    </div>

    <!-- Select: the option's value is sent, its text is what users see -->
    <div class="field">
      <label class="field-label" for="tax">Tax Bracket</label>
      <select id="tax" class="nexs__input" data-nexs-cell-addr="C16">
        <option value="0.1">10%</option>
        <option value="0.12">12%</option>
        <option value="0.22">22%</option>
        <option value="0.24" selected>24%</option>
        <option value="0.32">32%</option>
        <option value="0.35">35%</option>
        <option value="0.37">37%</option>
      </select>
    </div>

    <div class="field">
      <label class="field-label" for="appreciation">Annual Appreciation</label>
      <input type="text" id="appreciation"
             class="nexs__input"
             data-nexs-cell-addr="C17"
             placeholder="3%">
    </div>

    <div class="field">
      <label class="field-label" for="insurance">Insurance / Year</label>
      <input type="text" id="insurance"
             class="nexs__input"
             data-nexs-cell-addr="C18"
             placeholder="$5,000">
    </div>

    <div class="field">
      <label class="field-label" for="proptax">Property Tax Rate</label>
      <input type="text" id="proptax"
             class="nexs__input"
             data-nexs-cell-addr="C19"
             placeholder="0.5%">
    </div>
  </div>

  <!-- Outputs -->
  <div class="result">
    <div>Monthly Payment</div>
    <div class="amount">
      <span class="nexs__output_formatted" data-nexs-cell-addr="C12"></span>
    </div>
    <div>on a loan of
      <span class="nexs__output_formatted" data-nexs-cell-addr="C11"></span>
    </div>
  </div>

  <div class="summary">
    <h4>After 10 Years</h4>
    <div>Cash out
      <span class="nexs__output_formatted" data-nexs-cell-addr="F17"></span></div>
    <div>Tax savings
      <span class="nexs__output_formatted" data-nexs-cell-addr="G17"></span></div>
    <div>Net cost
      <span class="nexs__output_formatted" data-nexs-cell-addr="H17"></span></div>
    <div>Loan balance
      <span class="nexs__output_formatted" data-nexs-cell-addr="I17"></span></div>
    <div>Property value
      <span class="nexs__output_formatted" data-nexs-cell-addr="J17"></span></div>
    <div>Equity
      <span class="nexs__output_formatted" data-nexs-cell-addr="K17"></span></div>
  </div>
</div>

<!-- NExS app (handles calculations), hidden so only the custom UI shows -->
<div style="display:none;">
  <!-- Replace this UUID with your own app's ID if building from scratch -->
  <script class="nexs"
    src="https://static.nexs.com/js/nexs_embed.js"
    data-nexs-app-url="https://platform.nexs.com/app/ec7dcdee-dcea-4032-94ba-16782c9a1036">
  </script>
</div>

<script>
  // Text inputs receive the cell's raw value (0.04, 500000). After each
  // update, show the formatted text instead (4.000%, $500,000), except
  // in the input the user is currently editing.
  document.addEventListener('nexsappupdated', () => {
    document.querySelectorAll('input[type="text"].nexs__input').forEach(input => {
      if (input !== document.activeElement) {
        input.value = NEXS.cell(input.dataset.nexsCellAddr).text.trim();
      }
    });
  });
</script>

</body>
</html>

Every input and output is wired up by its class and data-nexs-cell-addr alone. The only JavaScript is the optional listener that formats the text inputs.

Tips

Hiding the NExS App

If you’re building a fully custom UI and don’t want the spreadsheet view visible, you can hide the embed container with CSS:

<div style="display:none;">
  <script class="nexs"
    src="https://static.nexs.com/js/nexs_embed.js"
    data-nexs-app-url="https://platform.nexs.com/app/YOUR-APP-ID">
  </script>
</div>

The Declarative API elements will still work even when the app view is hidden.

Combining with JavaScript

The Declarative API works alongside the JavaScript API. Use declarative binding for simple cases and JavaScript for complex logic:

<input type="text" class="nexs__input" data-nexs-cell-addr="B5">

<script>
  document.addEventListener("nexsappupdated", function() {
    // React to changes with JavaScript
    const value = NEXS.cell("B10").data;
    if (value > 1000) {
      alert("High value detected!");
    }
  });
</script>

Multiple Apps

When embedding multiple apps, always specify the app reference:

<!-- Inputs for first app -->
<input class="nexs__input" data-nexs-cell-addr="[0]B5">

<!-- Inputs for second app -->
<input class="nexs__input" data-nexs-cell-addr="[1]B5">

<!-- View selector for second app -->
<select class="nexs__viewselect" data-nexs-app="1"></select>