Function: linkSelection()
linkSelection<
Row,Datum>(store,o): () =>void
Defined in: packages/sdvplot/src/interact/link.ts:146
Wire a figure and/or a table to a selection store (J31). Figure: pointer hover → hover (see
LinkSelectionOptions.hover); every store change → highlight(figure, focusIds(state)). Table: row hover /
click → hover / selected; every store change → setSelection(selected), setExternalFilter(predicate) and
setHover with the first hover id. Loop-free: the store and the engine drop no-op updates, and the events a table
emits while the store is being applied to it are not written back (so a two-id hover is never narrowed to the one id
a table holds). One figure or one table per call; link several by calling again with the same store. The store
comes first because the call takes a figure, a table or both. Returns a teardown FUNCTION, not a handle: teardown is
all a link has, so useEffect(() => linkSelection(store, o), deps) is one line (brushFilter, nearestHover and
tooltip, which have more to do, return a handle with destroy()). The teardown clears hover when the store still
holds the hover this link wrote (as nearestHover's destroy does; an equal hover set first elsewhere is not one it
wrote): a figure redrawn under the pointer leaves no stale hover dimming the others. It then restores the view it
changed, so a figure or table unlinked and kept on the page shows no store state: the figure un-dims (once the last
link on it goes), its toggled marks get their own attributes back, and the table drops the brush filter and the hover
it showed. It never clears store state another writer owns: a brush's region and a selection stay in the store for
the views still linked. To replace a figure, tear its link down before linking the new one, which otherwise reads the
old figure's hover. Inert without a DOM, so server-rendered markup never changes. With select: "toggle", the
figure's marks are keyboard-reachable checkboxes over selected (LinkSelectionOptions.select).
Type Parameters
Row
Row
Datum
Datum = unknown
Parameters
store
SelectionStore<Row>
o
LinkSelectionOptions<Row, Datum>
Returns
() => void
Examples
import * as Plot from "@observablehq/plot";
import { createSelection } from "@sportsdataverse/sdvplot";
import { linkSelection } from "@sportsdataverse/sdvplot/interact";
import { linkIds } from "@sportsdataverse/sdvplot/plot";
import { createTable, defineTable } from "@sportsdataverse/sdvtables";
const rows = [
{ team: "KC", wins: 15, net_epa: 0.063 },
{ team: "BUF", wins: 13, net_epa: 0.19 },
{ team: "MIA", wins: 8, net_epa: -0.019 },
];
type Row = (typeof rows)[number];
const svg = Plot.plot({ marks: [Plot.dot(rows, { x: "wins", y: "net_epa", r: 6, render: linkIds(rows, "team") })] });
const spec = defineTable<Row>().columns((c) => [c.text("team"), c.int("wins")]).rowKey("team").build();
const table = createTable(spec, rows); // the engine a hydrated table or <SdvTable table/> renders
const store = createSelection<Row>();
linkSelection(store, { figure: svg });
linkSelection(store, { table });
table.setSelection(new Set(["BUF"])); // what a click on Buffalo's row calls: the store and the figure follow
svg; // Buffalo's dot lit, the rest dimmed
Games as checkboxes: click a cell, or Tab to it and press Enter or Space
import * as Plot from "@observablehq/plot";
import { createSelection } from "@sportsdataverse/sdvplot";
import { linkSelection } from "@sportsdataverse/sdvplot/interact";
import { linkIds } from "@sportsdataverse/sdvplot/plot";
// five of Brooklyn's 2025-26 games
const games = [
{ game_id: "0022500130", game_date: "2025-10-29", matchup: "BKN vs. ATL", wl: "L" },
{ game_id: "0022500149", game_date: "2025-11-02", matchup: "BKN vs. PHI", wl: "L" },
{ game_id: "0022500156", game_date: "2025-11-03", matchup: "BKN vs. MIN", wl: "L" },
{ game_id: "0022500173", game_date: "2025-11-05", matchup: "BKN @ IND", wl: "W" },
{ game_id: "0022500031", game_date: "2025-11-07", matchup: "BKN vs. DET", wl: "L" },
];
const svg = Plot.plot({
height: 60,
x: { type: "band" },
marks: [
Plot.cell(games, { x: "game_date", fill: "wl", ariaLabel: "matchup", render: linkIds(games, "game_id") }),
],
});
const store = createSelection<(typeof games)[number]>();
linkSelection(store, { figure: svg, select: "toggle" }); // each cell: role="checkbox", tabindex="0", aria-checked
svg.querySelector('[data-sdv-id="0022500173"]')?.dispatchEvent(new MouseEvent("click", { bubbles: true }));
svg; // the win at Indiana checked and lit, the rest dimmed: click a game, or Tab to it and press Enter or Space