LyteNyte Grid logo for light mode. Links back to the documentation home page.
Rows

Row Selection

Select individual or multiple rows using LyteNyte Grid's row selection system. Easily implement checkbox-based selection with support for bulk operations.

Enabling Row Selection

The rowSelectionMode property on LyteNyte Grid configures the row selection behavior the grid uses. It accepts one of the following values:

  • "none": Disables all built-in row selection behavior and prevents user interactions from selecting rows.
  • "single": Allows the user to select a single row. Selecting a new row clears any existing selection.
  • "multiple": Allows multiple rows to be selected, including additive selection behavior.

In addition to rowSelectionMode, the rowSelectionActivator property controls which user action selects a row. It accepts one of the following values:

  • "none": Disables all row-based selection interactions. Developers must provide a custom selection mechanism, such as selection checkboxes.
  • "single-click": Selects a row when the user clicks it.
  • "double-click": Selects a row when the user double-clicks it.

The demo below shows single-row selection configured to select a row with a single click. Other configurations, covered in later sections, support multiple selection modes or checkbox-based selection.

Enabling Row Selection

Fork code on stack blitzFork code on code sandbox

Multiple Row Selection

Set rowSelectionMode to "multiple" to allow users to select more than one row. Clicking a row toggles its selection state. Holding Shift while clicking another row selects the range between the two rows.

The demo below demonstrates these interactions.

Multiple Row Selection

Fork code on stack blitzFork code on code sandbox

Checkbox Selection

Selecting rows by clicking anywhere on the row can conflict with other grid interactions or diverge from common UX patterns. A common alternative is checkbox-based row selection.

LyteNyte Grid provides the api.rowHandleSelect helper to simplify checkbox selection logic, including support for shift-based range selection.

Checkbox Row Selection

Fork code on stack blitzFork code on code sandbox

The demo uses api.rowHandleSelect to handle checkbox interactions:

<GridCheckbox
checked={selected}
onClick={(ev) => {
ev.stopPropagation();
api.rowHandleSelect({ shiftKey: ev.shiftKey, target: ev.target });
}}
onKeyDown={(ev) => {
if (ev.key === "Enter" || ev.key === " ")
api.rowHandleSelect({ shiftKey: ev.shiftKey, target: ev.target });
}}
/>

Tip

Checkbox selection and click selection are not mutually exclusive in LyteNyte Grid. You can use both at the same time. Checkboxes are a great way to indicate to users that they can select rows.

Selecting All Rows

The selection checkbox demo allows you to select or deselect all rows in the grid using the header checkbox in the marker column. The demo uses the SelectAll component. However, you can achieve the same select-all behavior programmatically with the api.rowSelect method, as shown below:

api.rowSelect({ selected: "all" }); // select all rows
api.rowSelect({ selected: "all", deselect: true }); // deselect all rows

Selecting all rows only works if rowSelectionMode is set to "multiple".

Row Selection State

The row selection state is maintained by the row data source provided to the grid. The selection state determines which rows the grid marks as selected, and which rows are returned when you request the selected row set.

While each row data source maintains its own selection state in memory, all LyteNyte Grid data sources use the same row selection state representation.

Note

The explanation below applies to the built-in LyteNyte Grid data sources. If you use a custom data source, the behavior described here may not apply.

The row selection state may be one of two types:

  • linked: Used when the row selection mode is "multiple" and when the rowsIsolatedSelection property is set to false on the data source.
  • isolated: Used when the row selection mode is "single" or when rowsIsolatedSelection is set to true on the data source.

The code below shows how to set linked and isolated selection when using the client row data source.

// rowsIsolatedSelection is false by default, so it can be omitted.
const ds = useClientDataSource({ data: data, rowsIsolatedSelection: false });

The different row selection state modes primarily differ in how they handle selecting group rows. For flat datasets with no grouping, both modes behave identically.

Isolated Row Selection

Isolated row selection treats every row as individually selectable. As a TypeScript interface, it is represented as follows:

interface RowSelectionIsolated {
readonly kind: "isolated";
readonly selected: boolean;
readonly exceptions: Set<string>;
}

With isolated selection, selecting a group row does not select its children, and selecting all the child rows of a group does not select the parent. Each row maintains its own unique selection state.

RowSelectionIsolated works as an exclusion set. The selected property determines whether rows are selected by default. If selected is true, all rows are selected by default. If selected is false, no rows are selected by default. The exceptions set contains row IDs that invert the default selection:

  • If selected is true, any row with an ID in exceptions is not selected.
  • If selected is false, any row with an ID in exceptions is selected.

The demo below demonstrates isolated row selection. Notice that selecting a group row does not select its children. This is the intended behavior of isolated row selection.

Isolated Row Selection

Fork code on stack blitzFork code on code sandbox

Linked Row Selection

Linked row selection represents selection state as an inclusion/exclusion tree of nodes. The type interfaces are shown below. The root of the selection tree is the RowSelectionLinked type.

interface RowSelectNode {
readonly id: string;
children?: Map<string, RowSelectNode>;
selected?: boolean;
}
interface RowSelectionLinked {
readonly kind: "linked";
readonly selected: boolean;
readonly children: Map<string, RowSelectNode>;
}

The selection state of a row is determined by the closest node in the tree to that row, including the row itself.

Consider the tree below. Node A is not selected, but its child, Node Y, is selected, so the selection set includes Node Y. Node X is not selected because it does not override selection, and its parent is not selected.

On the other hand, since Node B is selected, Node W and Node U are also selected. This gives you a selection set that includes Node W and Node U.

Node A (selected = false)
|
| -- Node X
| -- Node Y (selected = true)
|
Node B (selected = true)
|
| -- Node W
| -- Node U
|

The linked row representation may appear complex at first, but it has some very desirable properties:

  • It compactly represents group selection states, especially when many groups are selected.
  • It works even when only a subset of rows is loaded, crucial for server data loading where only some group rows may be available.
  • It can be serialized into a short string, which is important for maintaining selection state in your application’s URL.

LyteNyte Grid compacts and collapses redundant nodes in the tree as the user selects rows. This keeps the tree as flat as possible while still representing the correct selection state. As a developer, you rarely need to interact with the selection state directly. In most cases, it is sufficient to call the rowsSelected method on the data source or the grid API. This method returns the currently selected row nodes.

The demo below demonstrates linked selection. Selecting all children of a group row also selects the group row, and selecting the group row selects all its children.

Linked Row Selection

Fork code on stack blitzFork code on code sandbox

Controlling Row Selection State

Each LyteNyte Grid row data source maintains an internal representation of row selection state. This internal state is uncontrolled, similar to the value of an <input> element without an onChange handler. You can control this state by setting the rowSelection property on the row data source.

To listen for updates, provide an onRowSelectionChange callback. For example:

const [selection, setSelection] = useState<Grid.T.RowSelectionLinked>({
kind: "linked",
selected: false,
children: new Map(),
});
const ds = useClientDataSource({
rowSelection: selection,
onRowSelectionChange: setSelection,
});

Warning

LyteNyte Grid’s row data sources enforce that the row selection state matches the rowsIsolatedSelection property on the data source. When providing your own row selection state, ensure that the selection type you pass matches the isolation setting.

Getting Selected Nodes

All row data sources implement the rowsSelected method. Since this method is implemented on the row data source, the grid API also makes it accessible. You can call it from whichever reference is most convenient.

The rowsSelected method returns the selected row nodes for the current row selection state. The nodes returned depend on the data source. For client-side data sources, such as the tree data source, all selected rows are available. For server data sources, only rows that have been loaded from the server are returned.

In the demo below, selecting rows and pressing “Alert Rows” fetches those rows and triggers an alert. Use this callback to retrieve selected row data in your application.

Get Selected Rows

Fork code on stack blitzFork code on code sandbox

The Alert Rows button uses the ds.rowsSelected method to retrieve the selected rows and alert the user with the count, as shown in the code below:

<button
data-ln-button="tertiary"
data-ln-size="md"
onClick={() => {
const selected = ds.rowsSelected();
if (!selected.rows.length) alert("There are currently no rows selected.");
if (selected.rows.length === 1) alert("1 row selected.");
if (selected.rows.length > 1) alert(`${selected.rows.length} rows selected.`);
}}
>
Alert Rows
</button>

Preventing Row Selection

The grid uses the row data source to handle row selection state, but selection is triggered through user interactions, such as clicking a row. LyteNyte Grid fires the onRowSelect callback whenever users select rows in the grid. You can use the event parameters to prevent selection or perform a different action that aligns with your application.

For example, use onRowSelect to limit row selection to 3 (or another number), as shown below.

Prevent Row Selection

Fork code on stack blitzFork code on code sandbox

From the demo code, notice that you can call preventDefault to stop the row selection from happening:

onRowSelect={({ preventDefault, rows, deselect, api }) => {
if (rows === "all" || deselect) return;
const current = api.rowsSelected().rows;
const finalSet = new Set([...rows, ...current.map((x) => x.id)]);
if (finalSet.size > 3) {
alert("You can only select a maximum of three rows");
preventDefault();
}
}}

Row Selection ID Universe

Each row data source maintains an ID universe, which is a complete set of all possible row IDs currently available in that data source.

  • For client-side data, this is the set of all possible rows for the current source configuration.
  • For server-side data, this is the set of all loaded rows.

LyteNyte Grid uses the ID universe to ensure selected row IDs are valid, meaning the ID of a selected row must exist in the grid.

If you want the grid to include row IDs that are not yet created but might be added later to the data source, you can specify additional IDs using the rowSelectionIdUniverseAdditions property on the data source, as shown below:

const ds = useClientDataSource({
rowSelectionIdUniverseAdditions: [
{ id: "unloaded-row-1", root: false },
{ id: "unloaded-row-2", root: true },
],
});

The root flag indicates that the row exists at the top level of the grid. This flag must be set and only impacts row selection when there are row groups present.

Only use rowSelectionIdUniverseAdditions when the rows you want to preselect are not immediately available in the data source.

To exclude rows from the ID universe, use the rowSelectionIdUniverseSubtractions property, as shown below. Rows excluded from the ID universe are not selectable. This behavior is useful when a row has a special use case and should not participate in normal selection behavior.

const ds = useClientDataSource({
rowSelectionIdUniverseSubtractions: new Set(["row-1"]),
});

Row Selection Reset Key

A row’s selection state is reset when the view changes in a way that makes existing rows invalid. Common actions that invalidate rows include:

  • Row grouping
  • Filtering
  • Sorting (only for server-side data)

The rowSelectKey property on the row data source can override the default reset behavior with your own key. It functions similarly to the dependency array in useMemo or useCallback hooks. Provide an array of values, and LyteNyte Grid shallow-compares the values whenever the key changes.

In the example below, clicking the Update Key button forces a row selection reset. The demo does this by setting rowSelectKey to an array containing a count, then incrementing the count whenever the button is clicked.

Resetting Row Selection

Fork code on stack blitzFork code on code sandbox

Next Steps

  • Row Pinning: Freeze rows at the top or bottom of the viewport.
  • Row Full Width: Create rows that span the full width of the viewport.
  • Row Master Detail: Render expandable row detail content, including nested grids.