Skip to content

Compatibility

Every number below was established by compiling and running against that version, not by reading a changelog. The method is noted for each.

Frameworks

RuntimeMinimumVerified againstNotes
React18.018.2.0, 19.2.8useSyncExternalStore is the floor — it landed in 18.0. Typechecked and server-rendered on 18.2.
Next.js13.4 (App Router)
12.0 (Pages Router)
16.3.2The package ships 'use client', so it imports into a server component directly. App Router support means React 18+, which 13.4 is the first stable release of.
Angular17.117.0.9, 17.3.12, 18.2.14, 19.2.25, 22.1.3The built output declares minVersion: "17.1.0" — signal input(), which landed in 17.1. Standalone components are required, so no NgModule setup.
Vue, Svelte, Solid, plain JSNo renderer package yet. @document-explorer/core is framework-free with zero dependencies, so the engine is usable today; the UI is not.
Node1822.22.3For @document-explorer/core and server rendering. Uses Intl only.

TypeScript

TypeScript is optional — the packages ship .d.ts and work fine from JavaScript.

If you do use it, 5.0+ is enough for the React and core packages. The Angular package's types follow whatever your Angular version requires (Angular 17 → TS 5.2, Angular 22 → TS 6.0).

Next.js

Both routers work. The package carries the 'use client' directive, so this compiles with no wrapper of your own:

tsx
// app/page.tsx — a SERVER component, no 'use client' needed
import { DocumentExplorer } from '@document-explorer/react';

export default function Page() {
  return <DocumentExplorer data={documents} search />;
}

Import the stylesheet once, in your root layout:

tsx
// app/layout.tsx
import '@document-explorer/react/styles.css';

One real constraint

React Server Components cannot pass functions across the boundary. A mapper written with functions therefore has to live in a client component:

ts
// ✗ from a server component — "Functions cannot be passed to Client Components"
const mapper = { id: (d) => d.document_id };

// ✓ dot paths are plain data, so they cross the boundary fine
const mapper = { id: 'document_id', name: 'document_title', type: 'kind' };

Every mapper field accepts a dot path as well as a function, so most mappings can be expressed serializably. Anything that genuinely needs a function goes in a 'use client' component — which is where your event handlers live anyway.

The same applies to columns with a render, and to renderers.

@document-explorer/core deliberately does not carry 'use client': it is pure logic with no hooks and no DOM, so you can normalize, search and sort on the server and ship less work to the browser.

Server rendering

The React package server-renders cleanly with no warnings — every DOM access sits inside an effect, useLayoutEffect falls back to useEffect off the browser, and ResizeObserver is feature-detected.

Verified with renderToString on React 18.2 and 19.2, and by Next.js static prerendering.

Browsers

Any browser with CSS Grid, custom properties and ResizeObserver — Chrome 88+, Edge 88+, Firefox 89+, Safari 14+.

Two features degrade rather than break on older engines:

  • :has() (Safari 15.4+, Chrome 105+) — used for the avatar tooltip. Without it the tooltip is clipped; the name is still in screen-reader text.
  • Pointer events — used for column resizing. The keyboard path ( ) is unaffected.

Bundlers

Vite, webpack, Rollup, esbuild, Next.js and the Angular CLI all work. The packages ship ESM and CJS with an exports map, and are sideEffects: false apart from the stylesheet.

Verified by installing the packed tarballs into scratch projects outside the monorepo and resolving ESM, CJS, types and CSS in each.

Released under the MIT License.