npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@open-grid/core

v0.3.0

Published

Framework-agnostic data grid engine.

Downloads

525

Readme

@open-grid/core

Framework-agnostic Open Grid engine for state, row models, column models, events, and data-grid behavior.

Use this package directly when building a custom renderer or a product-owned grid UI.

Install

npm install @open-grid/core

Quick Start

import { createColumnHelper, createGrid } from "@open-grid/core";

interface Person {
  id: string;
  name: string;
}

const column = createColumnHelper<Person>();
const grid = createGrid({
  data: [{ id: "1", name: "Mina" }],
  columns: [column.accessor("name", { header: "Name" })],
  getRowId: (row) => row.id,
});

const rows = grid.getRowModel().rows;

The core is DOM-free and framework-free. Product code owns data mutation, controlled state, and rendering.

Server Pagination Totals

Pass rowCount with manualPagination when the server knows the exact result total. grid.getRowCount() returns that normalized total and grid.getPageCount() derives the number of pages from the current page size. An explicit pageCount takes precedence when a backend exposes page counts without an exact row total.

Maintained renderers also use rowCount for exact WAI-ARIA row coordinates. Manual pagination without it reports an unknown accessible total instead of deriving one from pageCount.

Server Request Coordination

Use createServerRequestCoordinator({ getKey, request }) to share server request lifecycle behavior across framework integrations. Different keys run concurrently; a newer request for the same key aborts and supersedes the older request. The coordinator retains the last successful data during loading and error states and exposes explicit cancellation, retry, reset, subscriptions, and disposal without owning product query or transport policy.

See the server data guide for the typed request and state contracts.

Fit Columns To Width

Import fitColumnsToWidth and call fitColumnsToWidth(grid, width) to proportionally fit the currently visible leaf columns to an available inline width. The core repeatedly clamps columns at their minSize or maxSize and redistributes the remaining width, so one bounded column does not leave unused space while other columns can still grow or shrink.

Pass { columnIds: ["name", "status"] } as the third argument to fit only that visible subset. Unknown, duplicate, and hidden ids do not receive sizing entries; existing sizes for all other columns are preserved. A width below the selected minimum total or above its maximum total resolves to those bounds instead of violating column constraints. The width must be finite and non-negative. The resulting columnSizing still follows the normal controlled-state and onStateChange contract. The standalone command is tree-shakeable, so grids that do not use fitting do not carry the allocation algorithm.

Cell Edit History

Set editHistoryLimit to a positive number to retain bounded, product-owned cell edit transactions. Direct edits use one transaction per commit; paste and fill commit all accepted cells as one transaction. The default is 0, so read-only or history-free grids do not retain edit values.

Use grid.undoCellEdit() and grid.redoCellEdit() for replay, inspect availability with grid.getCanUndoCellEdit(), grid.getCanRedoCellEdit(), or grid.getCellEditHistoryState(), and reset retained values with grid.clearCellEditHistory(). Replay emits the same preventable, validated commit events with historyAction: "undo" | "redo"; product code still applies row data updates in onCellEdit. A commit prevented for async server approval is not added to local history.

Selector Subscriptions

Use grid.subscribeSelector(selector, listener, options) when product-owned UI only needs one derived grid value. The listener runs only when the selected value changes under Object.is; pass equalityFn for structural values and fireImmediately: true to receive the initial value. The returned function unsubscribes the listener.

const unsubscribe = grid.subscribeSelector(
  (currentGrid) => currentGrid.getCellEditHistoryState(),
  (history) => updateHistoryToolbar(history),
  { fireImmediately: true },
);

getCellEditHistoryState() retains its object identity while undo depth, redo depth, and limit are unchanged, so the default equality avoids product toolbar updates for unrelated sorting, filtering, focus, selection, and layout notifications. Use the existing grid.subscribe() when every grid notification is required.

See the project README for features, framework packages, and examples.