Refresh - National Design System

One call that tells every live NDS component the contents of a container changed. Use it after you add, remove, or replace rows, cards, or list items so filters, counters, and controls follow the new content instead of going quietly stale.

Overview

NDS.Init.refresh() ships in the main bundle and is available on every page. Pass it the container whose children changed. It walks the component registry and updates every component that has work in or around that container, so no component can be forgotten. Without it, each one needs its own call with its own argument, and every omission fails silently.

One call, one argument

The same call covers a table, a card grid, or any list. You never have to remember which component wants the content element and which wants an id.

Driven by the registry

Components are updated because they are registered, not because you listed them. A page that gains a component later is covered without changing your code.

Scoped to what changed

Components with nothing in the container are left alone. Call it with no argument to sweep the whole document instead.

Safe for server-driven lists

Nothing here re-sorts, re-pages, or re-filters a result set your server produced. Server pagination and AJAX filters are left exactly as they arrived.

Loads no bundles

A component whose bundle has not arrived is skipped rather than triggered. It has initialized nothing yet, and it reads the new content when it does load.

Safe to call twice

Calling it again on settled content leaves the page as it was, so you can call it after every mutation without tracking whether you already did. A client-side filter in scope re-announces its result with nds:filter:change each time.

Example

The shape every screen that edits a list needs: change the rows, then make one call.

Refresh after a row changes
const tbody = document.getElementById('requestsTableBody'); // Add, edit, or delete rows however your app does it tbody.appendChild(buildRow(record)); // Then tell NDS the contents changed NDS.Init.refresh(tbody);

What It Updates

Components fall into two groups, and the difference matters only if you are debugging. Components that own elements inside the container are re-scanned, so anything new is wired. Components that drive the list from outside it resolve their own connection to the container and update their view.

ComponentWhat happens
Anything inside the rowsRe-scanned and wired: dropmenus, formatted numbers, form controls, copy buttons, tooltips, and every other component with an element in the new content.
FilterRe-resolves its item set so new rows are filterable, and regenerates auto-scanned options so a value that arrived at runtime becomes selectable.
SelectionRecounts every widget, so the selected and total figures match the list.
PaginationRecomputed, and your current page is kept. Auto-pagination also re-paginates itself whenever page items are added or removed, so editing a row on page 3 leaves you on page 3.
NumbersRe-scanned. A new value gets locale digits and separators, and a new counter is armed to run when it scrolls into view. A counter that already finished carries data-animated and does not replay: remove that attribute first if you want it to count again.
EmptyNothing to do. It watches its own container and shows or clears the placeholder on its own.
SortNothing, by design. See Server-Driven Lists below.

Server-Driven Lists

When your server does the filtering, sorting, or paging, it has already decided which rows to send and in what order. This call never second-guesses that decision.

  • Sorting is never re-applied. A server-sorted page is a slice: the server ordered the whole set and sent you one page of it. Re-sorting that slice in the browser would order it by rendered text and silently contradict the server. If you want late rows folded into a client-side sort, call NDS.Sort.getInstance(table).refresh() yourself.
  • AJAX filters are skipped. A filter in AJAX mode owns its result set through its own request. Re-filtering those rows in the browser would match them against data-filter-value equality, which is not what a server does with full text search or a join, so rows the server deliberately returned could disappear. It would also shrink your option list to whatever the current page happens to contain.
  • Server pagination is untouched. A nav built from data-total-pages keeps its page count, its active page, and its record figures. Update those with NDS.Pagination.setTotalPages() and NDS.Pagination.updateRecords() when your response arrives.
  • No request is ever sent. This call only wires markup and recounts what is in the page. It never fetches, and it never submits a filter form.

Teardown

NDS.Init.destroy() is the mirror call. Use refresh() when the contents of a container changed and the container stays. Use destroy() when the container itself is about to go away. It returns the number of instances it released.

A page that loads once never needs this call. Nothing is removed, so nothing has to be released. A framework app is different: it swaps one view for another on every navigation. Each component in the old view holds listeners, observers, and menus that now point at markup the browser has thrown away. Nothing warns you, and the page keeps working, so the cost only shows up after many navigations.

Call it on the root element of the view you are about to remove, not on one list inside it. A filter toolbar can sit beside the grid it drives, so a call on the grid alone misses it.

Teardown is not one way. Each component clears its own init marker, so the same markup can be mounted again later with refresh().

Two components move their element out of your view while it is open. A FAB routes to a dock on <body>. A dropmenu with data-portal sends its open menu to the same place. Teardown puts both back where you wrote them, so the node leaves with your view instead of staying on the page after it.

Destroy a view before it is removed
// Mount a view, then keep it in step as its rows change NDS.Init.refresh(view); // Before the view is removed, release everything inside it NDS.Init.destroy(view); view.remove();

Usage Guidelines

Framework Views

A framework view needs no readiness check. Call window.NDS?.Init.refresh(view) after mount and NDS.Init.destroy(view) before unmount — that is the whole contract. A view that mounts before the runtime or one of its bundles arrives is picked up by NDS's own startup and arrival scans, and the optional chain covers the one moment where NDS does not exist yet. Do not write a poll or retry helper for this; there is nothing to wait for. The one exception is a component type the first paint never had anywhere: load its bundle once — await NDS.loadBundle('extras') — then call that component's init().

Best Practices

  • Call it once after the DOM settles, not once per row. A bulk insert of fifty rows needs one call at the end.
  • Pass the container whose children changed, such as the <tbody> or the grid wrapper. Passing a distant ancestor still works but does more scanning than it needs to.
  • Prefer it over a single component's reinit() when a list changed. Reaching for one component is how the others get forgotten, and none of them warn you.
  • Prefer it over NDS.Init.initialize(), which re-sweeps and re-tags the whole page. Use that only when you have replaced the entire page body.
  • You do not need it for content that was in the HTML at load. The loader already initialized that.
  • You do not need it after a filter, sort, or pagination interaction. Those components already keep each other in step.
  • Call it after your response has been written to the DOM, not when the request resolves. It reads the page, so the rows must be in place.
  • Do not call it from a handler for an event it can cause, such as a filter change. That is how a refresh loop starts.
  • Tear down what you remove before you remove it. Call NDS.Init.destroy(element) on it first. Refreshing does not clean up detached elements.
  • Server-driven list? Read Server-Driven Lists above before adding calls of your own. Most of what you might reach for is deliberately not done for you.

What it does not do

It updates components against the DOM as it stands. It does not fetch, build rows, or manage loading state, and it does not undo work you did by hand: a component you configured through its own API keeps that configuration. It also does not destroy anything. Elements you are about to remove need NDS.Init.destroy() first, described under Teardown above.

Reaching an Instance

A component stores its instance on the element it claims, as an nds{Name} property: el.ndsAccordion, el.ndsChart, el.ndsStepper, el.ndsSort. That property is how you reach an instance from a DOM node, and it is the same property NDS.Init.destroy() reads to find what to release.

Three namespaces also take the element and hand back the instance: NDS.Filter.getInstance(el), NDS.Sort.getInstance(el), and NDS.Upload.getInstance(el). No other namespace has getInstance, so use the element property for the rest.

// The instance sits on the element document.getElementById('salesChart').ndsChart.render(); // Filter, Sort, and Upload also expose a lookup const filter = NDS.Filter.getInstance(document.getElementById('resultsFilter'));

JavaScript API

Available on every page as part of the main bundle. No initialization required.

NDS.Init.refresh(container) // container: the element whose children changed. // Omit it to sweep the whole document. // After a create, edit, or delete NDS.Init.refresh(document.getElementById('requestsTableBody')); // After replacing a card grid with a server response grid.innerHTML = html; NDS.Init.refresh(grid); // Remove a row: tear down its listeners first, then refresh NDS.Init.destroy(row); row.remove(); NDS.Init.refresh(tbody); NDS.Init.destroy(container) // release every component instance inside container, // before the container itself is removed. Returns the // number released. Omit it to sweep the whole document. // A framework view: mount, keep in step, release NDS.Init.refresh(view); NDS.Init.destroy(view); // The rest of the NDS.Init surface await NDS.Init.audit() // report silent failures: unregistered inline icons, // filter and paged containers nothing ever claimed, // lang and dir disagreement, a nav link that should be // marked current, a stepper control fighting its form's // submit, and a framework wrapper that breaks the shell. // The checks live in nds-audit.min.js, which is never // auto-injected — this first call loads it and returns a // promise, so a production page ships zero audit bytes. NDS.Init.initialize() // full re-init of the page. Rarely what you want; // prefer refresh(container) NDS.Init.components // the component registry: {name, selector, init, critical} NDS.Init.config // the resolved init config // Load an injected bundle on demand, for content added after page load await NDS.loadBundle('extras');
Last Modified Date: 01/09/2026 - 11:56 PM
Was this page useful?
60% of users said Yes from 2843 Feedbacks