The ZingGrid API

ZingGrid defines a set of Custom Elements (tags) that you can use to construct a data table or interactive grid. As a set of custom elements, ZingGrid tags natively use standard CSS properties and attributes, react to JavaScript events, and act as you would expect normal HTML tags to behave.

Tag Usage

ZingGrid tags are an extension of native HTML and are used like any other tag:

CloseCopy Copied
<zing-grid data='[{"firstName":"John", "lastName":"Doe"}, {"firstName":"Jane", "lastName":"Doe"}]'>
  <zg-caption>Hello ZingGrid</zg-caption>
</zing-grid>

Since they are HTML tags, they support common attributes like id, class, title, etc.

CloseCopy Copied
<zing-grid id="my-grid" class="my-style"></zing-grid>

View the list of ZingGrid tags and the full list of HTML attributes

Attribute Usage

As extensions of native HTML elements, ZingGrid tags accept data attributes. Custom, predefined attributes are used to control the behavior of the grid, from quickly adding a styled caption-label to enabling search, sorting, and pagination.

CloseCopy Copied
<zing-grid
  data='[{"firstName":"John", "lastName":"Doe"}, {"firstName":"Jane", "lastName":"Doe"}]'
  caption="Hello ZingGrid"
  pager
  search
  sorter
></zing-grid>

When the grid is rendered, the feature attributes are evaluated and the matching DOM markup is constructed and added automatically.

Note: Some elements are auto-generated during the render process. They are listed on the API Elements page but not intended for manual use. If the element has no public attributes listed, this is a good indicator that it is added automatically for you.

User Content Model

Similar to native HTML elements, ZingGrid follows a strict content model. It defines which tags are allowed to be placed inside of each other. The following example shows the basic structure of the content model:

CloseCopy Copied
<zing-grid>

  <zg-data>
    <!-- may have a variety of defined parameters -->
    <zg-param></zg-param>
  </zg-data>

  <zg-header>
    <zg-caption></zg-caption>
    <zg-source></zg-source>
  </zg-header>

  <zg-colgroup>
    <!-- Define and format N numbner of columns of data -->
    <zg-column></zg-column>
  </zg-colgroup>

  <zg-card></zg-card>

  <zg-dialog></zg-dialog>

  <zg-pager></zg-pager>

  <zg-footer>
    <zg-caption></zg-caption>
    <zg-source></zg-source>
  </zg-footer>

</zing-grid>

Not all of these are required; you are free to construct your grids using the features you need. If required elements are omitted, ZingGrid will attempt to add them automatically to the grid on render. If elements are added incorrectly, it will attempt to correct it or add missing parent elements, where possible.

Although flexible, some elements are recommended to be added manually despite the fact they will be rendered if omitted. The best example is <zg-colgroup> with <zg-column>. You do not need to define <zg-column> elements, but if you do you should wrap them inside <zg-colgroup> directly. This will speed up render time depending on the number of data rows the grid displays. You can see if each element is optional or not on the API Elements page.

Generated Content Model

The User Content Model above illustrates how easy it is to get a grid up-and-running by adding only a few elements and attributes. The Generated Content Model shows what is actually rendered into the DOM from those configuration settings.

The generated source is important to understand if you want to customize the styling of the grid beyond choosing a prebuilt theme. See the guide on styling the grid for further information on customizing your grid's display.

CloseCopy Copied
<zing-grid>

  <!-- Grid Header (generated) -->
  <zg-header>

    <!-- Caption (user-added or generated) -->
    <zg-caption>

      <!-- Remove Selected Rows (generated) -->
      <zg-button action="removerecord"></zg-button>

      <!--
        Context Menu Button (generated)
        (mimics the right-click context-menu, but from a fixed location)
        (toggles the <zg-menu> Context-Menu shown below)
      -->
      <zg-button action="fixedmenu"></zg-button>

      <!--
        Column Menu (generated)
        (toggle per-column visibility)
      -->
      <!-- Toggle Button -->
      <zg-button action="menu"></zg-button>
      <!-- Dropdown -->
      <zg-menu>
        <zg-menuitem>
          <zg-button action="checkbox"></zg-button>
        </zg-menuitem>
      </zg-menu>

      <!-- Grid Search (generated) -->
      <zg-search></zg-search>

    </zg-caption>

    <!-- Source (user-added or generated) -->
    <zg-source></zg-source>

    <!-- Controls Bar (generated) -->
    <zg-control-bar>
      <!-- Select All Rows -->
      <zg-checkbox></zg-checkbox>
      <!-- Insert New Record -->
      <zg-button action="createrecord"></zg-button>
      <!-- Change Layout Mode -->
      <zg-layout-control>
        <zg-button action="layoutcard"></zg-button>
        <zg-button action="layoutrow"></zg-button>
      </zg-layout-control>
    </zg-control-bar>

  </zg-header>

  <!-- Use Inline or External Data Source (user-added) -->
  <zg-data>
    <!-- Configure Data With Parameters -->
    <zg-param></zg-param>
  </zg-data>

  <!-- Columns Group (user-added or generated) -->
  <!-- (analogous to HTML table '<colgroup>') -->
  <zg-colgroup>
    <!-- Format Column(s) (1 to N) -->
    <!-- (analogous to HTML table '<col>') -->
    <!-- Note: Not required, but if you need to customize one column, you need to specify them all -->
    <zg-column></zg-column>
  </zg-colgroup>

  <!-- Custom 'Card' Layout Template (user-added or generated) -->
  <!-- Note: Replaces the normal <zing-grid layout="card"> display -->
  <zg-card><!-- User Defined Code --></zg-card>

  <!-- Grid Data Table 'Head' (generated) -->
  <!-- (analogous to HTML table '<thead>') -->
  <zg-head>
    <zg-row>
      <!-- 'Head' Cells (1 to N) -->
      <!-- (analogous to HTML table '<th>') -->
      <zg-head-cell></zg-head-cell>
    </zg-row>
    <!-- Filter Column(s) Controls -->
    <zg-row>
      <zg-filter></zg-filter>
    </zg-row>
    <!-- Optional Aggrigation Cell (sum, average, etc.) -->
    <zg-row>
      <zg-cell></zg-cell>
    </zg-row>
  </zg-head>

  <!-- Grid Data Table 'Body' (generated) -->
  <!-- (analogous to HTML table '<tbody>') -->
  <zg-body>
    <zg-row>
      <!-- 'Body' Cells (1 to N) -->
      <!-- (analogous to HTML table '<td>') -->
      <zg-cell></zg-cell>
      <!-- <zg-card> Instance (conditional) -->
      <!-- (if user-defined <zg-card> template added, its result rendered here -->
      <zg-card></zg-card>
    </zg-row>
  </zg-body>

  <!-- Grid Data Table 'Foot' (generated) -->
  <!-- (analogous to HTML table '<tfoot>') -->
  <zg-foot>
    <!-- Optional Aggrigation Cell (sum, average, etc.) -->
    <zg-row>
      <zg-cell></zg-cell>
    </zg-row>
  </zg-foot>

  <!-- Drag-Select Multiple Cells For Action (generated) -->
  <zg-selector-mask></zg-selector-mask>
  <!-- The Currently-Selected Cell (generated) -->
  <zg-focus></zg-focus>

  <!-- The Pagination Element (user-added or generated) -->
  <!-- (Contains 'per page' dropdown, next/previous buttons, and total records data) -->
  <!-- (Location of elements controlled by slot naming) -->
  <zg-pager>
    <zg-select action="pagesize"></zg-select>
    <zg-button action="reload"></zg-button>
    <zg-button action="firstpage"></zg-button>
    <zg-button action="prevpage"></zg-button>
    <zg-text>Page</zg-text>
    <zg-input action="currpage"></zg-input>
    <zg-text>of</zg-text>
    <zg-text value="pagecount"></zg-text>
    <zg-button action="nextpage"></zg-button>
    <zg-button action="lastpage"></zg-button>
    <zg-text>Rows</zg-text>
    <zg-text value="startrow"></zg-text>
    <zg-text>-</zg-text>
    <zg-text value="endrow"></zg-text>
    <zg-text>of</zg-text>
    <zg-text value="rowcount"></zg-text>
  </zg-pager>

  <!-- Grid Footer (generated) -->
  <zg-footer>
    <!-- Caption Alternate Position (generated-only) -->
    <zg-caption></zg-caption>
    <!-- Source Alternate Position (generated-only) -->
    <zg-source></zg-source>
  </zg-footer>

  <!-- Internal Dialogs (modal overlays - generated) -->
  <!-- User-Defined Dialogs (user-added - <zg-dialog type="custom">) -->
  <zg-dialog></zg-dialog>

  <!-- Inline-Edit Grid Row (generated) -->
  <zg-editor-row></zg-editor-row>

  <!-- Grid Action(s) Context Menu (generated) -->
  <zg-menu>
    <!-- Contains any combination of <zg-menugroup>, <zg-menuitem>, and <zg-separator> -->
    <zg-menu-group group="insert-record-group">
      <zg-menuitem></zg-menuitem>
      <zg-menuitem></zg-menuitem>
    </zg-menu-group>
    <zg-menuitem>
      <zg-button action="cancelrecord"></zg-button>
    </zg-menuitem>
    <zg-separator action="action"></zg-separator>
  </zg-menu>

  <!-- Status Messages (generated) -->
  <zg-status></zg-status>

  <!-- Grid Loading Mask (user-added or generated) -->
  <zg-load-mask></zg-load-mask>
</zing-grid>

Attribute Versus Element

It may often appear that ZingGrid has some attributes and elements that share the same purpose. This is by design, and offers convenience to the developer.

For most use cases, setting the attribute will be easier and faster then providing the equivalent markup elements. You should only need to add markup if you wish to customize the default behavior. Features added via attributes have their corresponding elements created and added to the grid automatically on render.

For example, take this grid:

CloseCopy Copied
<zing-grid
  data='[{"firstName":"John", "lastName":"Doe"}, {"firstName":"Jane", "lastName":"Doe"}]'
  caption="Hello ZingGrid"
></zing-grid>

On render, the <zg-caption> tag is generated to the grid in the correct location:

CloseCopy Copied
<zing-grid
  data='[{"firstName":"John", "lastName":"Doe"}, {"firstName":"Jane", "lastName":"Doe"}]'
  caption="Hello ZingGrid"
>
  <zg-header>
    <zg-caption>Hello ZingGrid</zg-caption>
  </zg-header>
</zing-grid>

Conversely, you can add the caption via markup and the attribute will be added to the grid. Do this if you need to customize the caption beyond plain text.

CloseCopy Copied
<zing-grid data='[{"firstName":"John", "lastName":"Doe"}, {"firstName":"Jane", "lastName":"Doe"}]'>
  <zg-caption><em>Hello ZingGrid<em></zg-caption>
</zing-grid>
Hello ZingGrid

Since the caption is only added to the <zg-header> tag when you add the attribute to <grid-grid caption="...">, you might think to try adding it inside <zg-footer> directly:

CloseCopy Copied
<zing-grid>
  <zg-footer>
    <zg-caption>Hello World</zg-caption>
  </zg-footer>
</zing-grid>

However, it is easier to specify the caption's position via its own predefined attributes:

Footer

CloseCopy Copied
<zing-grid>
  <zg-caption position="bottom">Hello World</zg-caption>
</zing-grid>
Hello World

Both

CloseCopy Copied
<zing-grid>
  <zg-caption position="both">Hello World</zg-caption>
</zing-grid>
Hello World

If both the attribute and the element(s) are added by the user, the attribute value will take precedence. Take the following for example:

CloseCopy Copied
<zing-grid
  data='[{"firstName":"John", "lastName":"Doe"}, {"firstName":"Jane", "lastName":"Doe"}]'
  caption="Hello ZingGrid"
>
  <zg-caption>Alternate Caption</zg-caption>
</zing-grid>

In the rendered example, you can see the attribute took precedence over the matching element.

By having the attribute take precedence, the grid can read changes to the attribute after render and update the element accordingly. For example, if the caption attribute value is updated, the element value will update and you'll see the new value in the grid. If the attribute is removed, the caption element will hide and won't be visible on screen.

Try changing the caption in the accompanying demo. If you inspect the grid, you'll see the caption attribute is updated, which in turn updates the <zg-caption>'s text content.

Syncing between attribute and element is unidirectional. Changes to the element directly after render will not cause the grid to update. If you cannot update via the attribute after render, you'll need to manually refresh the grid via the grid:refresh event. You can see all of the grid events on the API Events page.

Altenate Caption

ZingGrid and HTML Templates

Some ZingGrid features generate complex markup structures based on a smaller set of config or control items set by the user. In these use cases, you are providing a template similar to a native html <template> tag. In fact, this is what happens in the background; ZingGrid takes the user-templating code and applies it to a <template>. ZingGrid then renders the target grid markup for you from this template.

Take <zg-column> for example. When you define a custom render template for it, you are providing ZingGrid with an html template to use:

CloseCopy Copied
</zing-grid data='[{"firstName":"John", "lastName":"Doe"}, {"firstName":"Jane", "lastName":"Doe"}]'>
  <zg-colgroup>
    <zg-column index="firstName,lastName" header="Name">
      Name: <strong>[[index.firstName]] [[index.lastName]]</strong>
    </zg-column>
  </zg-colgroup>
</zing-grid>

This is the same as adding it as an HTML template:

CloseCopy Copied
</zing-grid data='[{"firstName":"John", "lastName":"Doe"}, {"firstName":"Jane", "lastName":"Doe"}]'>
  <zg-colgroup>
    <zg-column index="firstName,lastName" header="Name">
      <template>
        Name: <strong>[[index.firstName]] [[index.lastName]]</strong>
      </template>
    </zg-column>
  </zg-colgroup>
</zing-grid>

ZingGrid interprets the <zg-column> template code and uses it to override the normal <zg-cell> automatically.

Name: [[index.firstName]] [[index.lastName]]

External Templates

Defining numerous templates for a complex grid design, or reusing the same template on multiple grids may become cumbersome. Instead, you can point to an external template to use:

CloseCopy Copied
<zing-grid data='[{"firstName":"John", "lastName":"Doe"}, {"firstName":"Jane", "lastName":"Doe"}]'>
  <zg-caption>External Template<zg-caption>
  <zg-colgroup>
    <zg-column index="firstName,lastName" header="Name" renderer-template="colTemplate"></zg-column>
  </zg-colgroup>
</zing-grid>

<template id="colTemplate">
  Name: <strong>[[index.firstName]] [[index.lastName]]</strong>
</template>

For generative processes like <zg-column> or <zg-card>, where the contents of the tag are used to generate markup elsewhere in the grid, we recommended using a <template> tag to match web standards. For all other tags, like <zg-caption>, where the element is the final rendered result, a template isn't necessary; nested content will render as-is in place.

External Template

Using CSS with ZingGrid

As Custom Elements, you are able to bind CSS directly to ZingGrid tags. For certain elements within a tag's shadowDOM, you can target them with our CSS Variable API system.

Inline CSS

CloseCopy Copied
</zing-grid
  data='[{"firstName":"John", "lastName":"Doe"}, {"firstName":"Jane", "lastName":"Doe"}]'
  style="border: 10px solid #003749;"
>
  <zg-caption style="background: #ef5350;">Hello World</zg-caption>
</zing-grid>

External CSS

CloseCopy Copied
<style>
  zing-grid { border: 10px solid #003749; }
  zg-caption { background: #ef5350; }
</style>

</zing-grid data='[{"firstName":"John", "lastName":"Doe"}, {"firstName":"Jane", "lastName":"Doe"}]'>
  <zg-caption>Hello World</zg-caption>
</zing-grid>

CSS Variables

ZingGrid also exposes a CSS Variables-based API, used primarily for the built-in themes and creating custom themes. There are also a few instances where you might need to style an element inside the tag's ShadowDOM, where CSS Variables are the only recourse. For most use cases, using direct inline/externtal styling will be the smoother experience.

View the full list of ZingGrid CSS Variables

CloseCopy Copied
<style>
  :root {
    --zing-grid-border: 10px solid #003749;
    --zg-caption-background: #ef5350;
  }
</style>

</zing-grid data='[{"firstName":"John", "lastName":"Doe"}, {"firstName":"Jane", "lastName":"Doe"}]'>
  <zg-caption>Hello World</zg-caption>
</zing-grid>

It is recommended to define css-variable overrides inside the :root {} selector for maximum cross-browser support. You can also define css variables within the 'scope' of an element, although this is less universally supported:

CloseCopy Copied
zing-grid { --zing-grid-border: 5px solid red; }
zing-grid[layout="card"] { --zing-grid-border: 3px solid blue; }

Hello World

Generated Elements

Some ZingGrid tags act as configuration items and are not visible when the grid is rendered. Styling these elements will have no effect on screen:

  • <zg-colgroup>
  • <zg-column>*
  • <zg-data>
  • <zg-param>

*<zg-column> is a tricky case. It behaves the same as a table's <col> element in native HTML. As such, it has a limited subset of CSS properties that will affect it:

  • background
  • border
  • visibility: collapse1
  • width2

  • 1
    visiblity: collapse; has inconsistent cross-browser behavior and is discouraged.
  • 2
    While width does work, cell widths are generated dynamically (and with min-width), and your setting will likely not work as intended.

Custom Grid CSS Classes

You also have the ability to set a custom, CSS class on all grid rows, columns, and cells. Since they are auto-generated, you define the classes on the <zing-grid> tag itself:

  • row-class="myRowClass"
  • col-class="myColClass"
  • cell-class="myCellClass"
CloseCopy Copied
<style>
  .myRowClass { border: 5px solid #003749; }
  .myColClass:nth-of-type(even) { color: #fff; background: #ef5350; border: #ef5350; }
  .myCellClass:nth-of-type(odd) { background: yellow; }
</style>

<zing-grid
  data='[{"firstName":"John", "lastName":"Doe"}, {"firstName":"Jane", "lastName":"Doe"}]'
  row-class="myRowClass"
  col-class="myColClass"
  cell-class="myCellClass"
></zing-grid>

Column Override

Add cell-class="myOverrideClass" to individual <zg-column> tags to override on a per-column basis.

CloseCopy Copied
<style>
  /* Applies to all body cells */
  .myCellClass { background: #ef5350; }
  /* Override specific cells */
  .cell-lastname { background: yellow; }
</style>

<zing-grid
  data='[{"firstName":"John", "lastName":"Doe"}, {"firstName":"Jane", "lastName":"Doe"}]'
  cell-class="myCellClass"
>
  <zg-colgroup>
    <zg-column index="firstName"></zg-column>
    <zg-column index="lastName" cell-class="cell-lastname"></zg-column>
  </zg-colgroup>
</zing-grid>

Compact Display

Add compact to <zing-grid> to show a compact version of the grid. This works for all built-in themes.

CloseCopy Copied
<zing-grid
  data='[{"firstName":"John", "lastName":"Doe"}, {"firstName":"Jane", "lastName":"Doe"}]'
  compact
></zing-grid>

Normal

Compact

Using JavaScript with ZingGrid

ZingGrid tags as Custom Elements have access to the standard JavaScript DOM API.

Element Manipulation

After the grid renders, you are able to query select any lightDOM elements and manipulate them. For example, you can update the caption either by changing the attribute value or the <zg-caption> text directly.

CloseCopy Copied
<zing-grid id="myZingGrid" caption="Original Caption"></zing-grid>

<script>
  let zgRef = document.querySelector('#myZingGrid');
  let zgCaption = zgRef.querySelector('zg-caption');
  zgCaption.textContent = 'New Caption';
</script>

If you inspect the demo after changing the caption, you'll notice that the caption attribute on ZingGrid was not updated! As we saw in the Attribute Versus Element section, ZingGrid has unidirectional sync controlled by the attribute, not the corresponding element. So when updating grid elements, it is recommended to update the attribute, which will sync the matching elements.

CloseCopy Copied
<zing-grid id="myZingGrid" caption="Original Caption"></zing-grid>

<script>
  let zgRef = document.querySelector('#myZingGrid');
  zgRef.setAttribute('caption', 'New Caption');
</script>
Update Caption: New Caption

Native Events

ZingGrid exposes many lifecycle events for you to hook into to customize the grid's behavior. Simply add an event listener to control when to execute your custom code.

For example, the grid:ready event is emitted from the <zing-grid> element when it has finished rendering. Add a listener for it and then execute your code.


The record:click event is emitted when you click on a body <zg-row>. Test it out in the accompanying demo:

CloseCopy Copied
<zing-grid
  id="myGrid"
  data='[{"firstName":"John", "lastName":"Doe"}, {"firstName":"Jane", "lastName":"Doe"}]'
  caption="Click a row to animate the grid"
>
</zing-grid>

<style>
  @keyframes BOUNCE {
    0%, 100% { transform: translateY(0); }
    50% { transform: translateY(-15px); }
  }
  .animate { animation:BOUNCE .5s; }
</style>

<script>
  let zgRef = document.querySelector('#myGrid');
  zgRef.addEventListener('record:click', e => {
    zgRef.classList.add('animate');
  });
</script>

View the full list of events on the API Events page.

Custom Events

Bind normal event actions:

CloseCopy Copied
<zing-grid data='[{"firstName":"John", "lastName":"Doe"}, {"firstName":"Jane", "lastName":"Doe"}]'>
  <zg-caption onclick="handleClick">Click me</zg-caption>
</zing-grid>

<script>
  function handleClick() {
    alert('Caption clicked!');
  }
</script>

Or a modern event listener to separate concerns:

CloseCopy Copied
<zing-grid id="myZingGrid" data='[{"firstName":"John", "lastName":"Doe"}, {"firstName":"Jane", "lastName":"Doe"}]'>
  <zg-caption id="myCaption">Click me</zg-caption>
</zing-grid>

<script>
  document.querySelector('#myCaption').addEventListener('click', handleClick);

  function handleClick() {
    alert('Caption clicked!');
  }
</script>
Click Me

Using ZingGrid With Frameworks

ZingGrid can be used with modern frameworks like React, Vue, and Angular, just like native HTML or other Custom Elements. When using these, take note that they are abstracting and virtualizing the DOM, which may introduce considerations not normally encountered with static HTML implementations.

Please view the integration examples for your specific framework for further details and examples.

loadingloadBgloadBgloadBgloadBgloadBgloadBgloadBgloadBgloadBgloadBgloadBgloadBgloadBgloadBgloadingloadingloadingloadingloadingloadingloadingloadingloadingloadingloadingloadingloadingloadingloadingloadingloadingloadingloadingloadingloadingloading