Demo / Plugins / Base

Base plugins and the plugin system

OmniGrid is built from a framework-agnostic core that owns rows, columns, viewport geometry, virtualization, events, and slots. The core ships with no DOM and no framework imports. Thin adapters bind the core to a UI stack (React, and more to come). Optional behavior is delivered as plugins — self-contained modules that implement a small interface, get registered into the grid, and either augment data processing or mount controls into slots.

The base plugins are free, open-source (MIT), and cover the most common interactive behaviors: column filtering, row selection, column sorting, datapagination, and column resize. Each ships as its own package so you install only what you use. Together they extend OmniGrid with everything from a single sortable header click to server-side paging, and each one can be configured or replaced to fit your domain.

01

Modular architecture

The system splits responsibility across three layers. The core (`@omnigrid/core`) is a portable engine: it manages state, runs the data pipeline, computes virtualization, and owns the slot manager. The adapter (`@omnigrid/react`) renders that state with a particular UI framework, translating headless content descriptions into DOM or framework nodes. Plugins sit between the two — they receive the core's `GridApi` and can read state, transform data, subscribe to events, and mount controls — all without importing any framework code themselves.

Every plugin implements the minimal GridPlugin<T> interface:

Loading...

The name is a unique identifier. The register method receives the grid API, performs setup, and returns a cleanup function called when the plugin is unregistered or the grid is destroyed. The two optional methods let a plugin contribute CSS classes or inline styles to rows — for example, the selection plugin marks selected rows with a CSS class.

02

Registering and composing plugins

Plugins are composed by instantiating them and passing the instances through the plugins prop. The grid registers each one in order, so plugins can interact with each other through shared API events. Because each base plugin is its own package, you install only what you need:

Loading...

Then pass the instances to the grid:

Loading...

Instantiate plugins with useMemo (or outside the render) so the same instance survives re-renders — the grid reads the plugin options at construction time and subscribes to its callbacks. See the live examples for filtering, sorting, selection, pagination, and resize.

03

Working with data

The grid maintains a data pipeline. The raw data passed via the data prop is the starting point. Each registered data processor receives the output of the previous one, forming a chain. When any processor calls api.setData(), the pipeline re-runs and the grid re-renders. This is how base plugins work: the sorting plugin registers a processor that reorders rows, and the pagination plugin registers a processor that slices rows into pages.

Plugins can operate in two modes. In client mode the plugin transforms the data locally — filtering, sorting, or paginating the data the grid already holds. In server mode the plugin skips local transformation entirely: it calls onChange with the requested parameters (page, page size, or sort model), and the host fetches the result and feeds it back through the (page, page size, or sort model), and the host fetches the result and feeds it back through the data prop. This keeps the pipeline consistent whether data is processed locally or

04

Placing controls with slots

OmniGrid exposes four slots where plugins — and your own code — can place UI controls around the grid: top, bottom, left, and right. Each slot is a region outside the scrollable cell area that moves with the grid but is not virtualized. A plugin mounts content via api.slots.mount(), which returns a handle whose unmount()method removes it:

Loading...

Three options control placement within a slot:

  • priority — ordering within the slot (lower values render first).
  • position — alignment group: "start" | "center" | "end". The adapter renders each group side by side within the slot.
  • id — stable identifier. Re-mounting with an existing id replaces the previous content instead of duplicating it.

Slot content is headless — the core stores an opaque value and the adapter materializes it at render time. This means a plugin never imports React, Vue, or the DOM. Five content shapes are recognized:

Loading...

The pagination plugin, for example, mounts SlotNodeContent buttons (first, prev, next, last) into the bottom slot. The selection plugin mounts a checkbox column header node. All of this is framework-agnostic — the React adapter renders the same declarative nodes as real React elements without the plugins knowing it.

05

Writing your own plugin

Because the plugin interface is tiny and headless, writing a custom plugin is straightforward. A plugin can read grid state (columns, data, viewport), transform rows via a data processor, subscribe to grid events, mount controls into slots, and expose a public API for the host to call. The example below is a text-filter plugin that demonstrates all of these capabilities:

Loading...

It is registered the same way as a base plugin:

Loading...
06

Base plugins at a glance

ColumnFilterPlugin

Open a column filter popup from the header to filter rows by operator and value. SupportsContains, Equals, Greater than, In range, Blank, and more.

@omnigrid/column-filter-plugin

SortingPlugin

Click a column header to sort. Supports multi-sort (Ctrl / Shift), a custom comparator per column or globally, and server-side sorting via onChange.

@omnigrid/sorting-plugin

QuickFilterPlugin

Global search input mounted into the top slot with debounced, comma-separated multi-term matching across all searchable columns. Columns with searchable: false are excluded, and slot, position, placeholder, and debounce can be configured.

@omnigrid/quick-filter-plugin

SelectionPlugin

Single or multiple row selection via click or optional checkboxes. Supports selectability predicates, a select-all header checkbox, and live onSelectionChange callbacks.

@omnigrid/selection-plugin

PaginationPlugin

Splits rows into pages. Client mode slices data locally via a data processor; server mode delegates fetching to the host. Renders navigation, page-size, and row-info blocks into top / bottom slots with configurable placement.

@omnigrid/pagination-plugin

ResizePlugin

Draggable column resize handles with double-click auto-fit. Adapts to pinned and grouped columns, respects per-column min/max width constraints, and exposes onResizeStart / onResize / onResizeEnd callbacks.

@omnigrid/resize-plugin