Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

<perspective-viewer> Custom Element library

<perspective-viewer> provides a complete graphical UI for configuring the perspective library and formatting its output to the provided visualization plugins.

Once imported and initialized in JavaScript, the <perspective-viewer> Web Component will be available in any standard HTML on your site. A simple example:

<perspective-viewer id="view1"></perspective-viewer>
<script type="module">
    import perspective from "@perspective-dev/client";
    import "@perspective-dev/viewer";

    const viewer = document.getElementById("view1");
    const worker = await perspective.worker();
    await worker.table(data, { name: "my_table" });

    await viewer.load(worker);
    await viewer.restore({ table: "my_table" });
</script>

load() binds the viewer to a Client, and restore() selects which of that client’s Tables to show via the table field. Because load() alone selects no table, it does not render — the pair guarantees exactly one atomic render.

Passing a Table directly is still supported as a legacy shorthand,

await viewer.load(table);

… which is internally equivalent to:

await viewer.load(await table.get_client());
await viewer.restore({ table: await table.get_name() });
Always give your Table a name. When name is omitted a random one is assigned, so the table field in a token from save() will not match the table after a page reload, and restore() will fail.

Attributes

<perspective-viewer> reads one HTML attribute, theme, which selects the initial theme by the --psp-theme-name a loaded stylesheet declares. Every other setting is applied through the JavaScript API, typically restore(), and the viewer reflects the active theme back onto the same attribute when the user picks one:

<perspective-viewer theme="Pro Dark"></perspective-viewer>
await viewer.restore({ columns: ["Sales", "Profit"], group_by: ["Region"] });

Editor and tooling support

@perspective-dev/viewer ships a Custom Elements Manifest at dist/custom-elements.json, advertised by the customElements field of its package.json. It enumerates the element’s methods, static methods, events, the theme attribute, slots, the tab shadow part and every theme CSS custom property, so editors, Storybook and documentation generators that read the manifest can offer completion and reference tables without any further setup.

UI Features

The viewer provides an interactive side panel with:

  • Column list - drag and drop columns to configure group_by, split_by, sort, and filter fields.
  • New Column button - opens an expression editor for creating computed columns via the expression language.
  • Plugin selector - switch between the visualization plugins registered on the page. @perspective-dev/viewer-datagrid provides Datagrid; @perspective-dev/viewer-charts provides X Bar, Y Bar, Y Line, Y Scatter, Y Area, X/Y Scatter, X/Y Line, Density, Treemap, Sunburst, Heatmap, Candlestick, OHLC, Map Scatter, Map Line and Map Density.
  • Theme selector - toggle between available themes.
  • Export - download the current view as CSV or Arrow.
  • Copy - copy the current view to the clipboard.
  • Reset - restore the viewer to its default configuration.

Methods

A <perspective-viewer> hosts one or more panels. Methods which address a single panel take an options-dict with an optional panel id, defaulting to the active panel — e.g. await viewer.save({ panel: "PANEL_ID_0" }).

Binding

MethodDescription
load(client)Bind a Client (or, legacy, a Table) to the viewer
eject(options?)Remove a Client and dispose every panel bound to it
delete()Release the element’s resources
getClient(options?)Get a bound Client
getTable(options?)Get a panel’s Table
getView(options?)Get a panel’s View — mode selects "live" (default), "clone" or "auto"
getViewConfig(options?)Get a panel’s ViewConfig

View lifecycle

By default getView() returns the panel’s own live View. The viewer owns it: every config change replaces it, and auto-pause (the element scrolled out of view, display: none, or a backgrounded tab) or delete() deletes it. Any call on a live View can therefore fail with “View already deleted”, even one already in flight, and it must never be delete()d by the caller. While a panel is auto-paused or has not rendered yet it has no live View, and getView() rejects with No View for panel "<name>"; setAutoPause(false) forces one to exist for every panel, at the cost of a live subscription each.

A reference that has to outlive the render lifecycle should not borrow the viewer’s View at all. mode: "clone" builds a new View from the panel’s effective config (the element’s global filter included) which is independent of rendering and pause, and which the caller owns and must delete():

for (const panel of viewer.getPanelNames()) {
    const view = await viewer.getView({ panel, mode: "clone" });
    const arrow = await view.to_arrow();
    await view.delete();
}

mode: "auto" returns the live View when one exists and a clone otherwise. Ownership follows whichever was returned, so use it only where the caller never deletes the result.

Configuration

MethodDescription
save(options?)Serialize one panel’s configuration
restore(config, options?)Apply a configuration to one panel
saveWorkspace()Serialize the whole element — every panel, plus layout and global filters
restoreWorkspace(config)Apply a workspace config update; absent fields are left unchanged
reset(all?, options?)Reset configuration (pass true to also reset expressions)
resetError()Clear the error overlay

Panels

MethodDescription
addPanel(config)Add a panel, returning its generated id
removePanel(id)Remove a panel
getPanelNames()List panel ids
getActivePanel() / setActivePanel(id)Get or set the active panel

Output

MethodDescription
export(options?)Export a panel — see the export methods below
download(options?)Export and download as a file
copy(options?)Copy a panel to the clipboard

export(), download() and copy() all take a method, one of "csv", "json", "ndjson", "arrow", "arrow-lz4" or "arrow-zstd" — each with -all and -selected variants (e.g. "csv-selected", "arrow-zstd-all") — plus "html", "json-config", and "plugin". The "arrow-lz4" and "arrow-zstd" methods write the Arrow IPC stream with LZ4 or ZSTD body compression. The "plugin" method asks the plugin to render itself, which produces a PNG for charts and text for the datagrid. | getSelection(options?) / setSelection(...) | Get or set the selected region | | getEditPort(options?) | Get a panel’s edit port | | getRenderStats(options?) | Get render timing statistics |

Rendering and chrome

MethodDescription
flush()Wait for any pending UI updates to complete
resize(options?)Redraw, optionally at a {dimensions: {width, height}} size hint
setAutoSize(bool) / setAutoPause(bool) / setThrottle(ms)Render policy
toggleConfig(force?)Toggle the settings sidebar
toggleColumnSettings(...)Toggle the column settings sidebar
resetThemes(themes?)Re-detect or explicitly set available themes
restyleElement()Re-read CSS and repaint
getPlugin(name?) / getAllPlugins()Look up registered plugins

The element class also has page-wide static methods:

MethodDescription
registerPlugin(name)Register a plugin custom element
setPluginConfigDefaults(defaults, options?) / setColumnConfigDefaults(defaults, options?)Replace plugins’ plugin_config / columns_config defaults
getPluginConfigDefaults() / getColumnConfigDefaults()Read the replaced defaults

See Saving and restoring UI state for the save/restore formats and the panel selector, Plugin render limits for getPlugin, and Configuration defaults for the defaults methods.