# Introduction

> A high-performance, framework-agnostic data grid web component for JavaScript, React, Angular, and Vue. Zero dependencies, 100k+ rows, virtualized rendering.

## CORPUS RETRIEVAL STRATEGY

Five corpus variants are published. **Pick the one that covers your stack:**

| File | Use when |
|------|----------|
| `llms-full-angular.txt` | Working in an Angular project |
| `llms-full-react.txt` | Working in a React project |
| `llms-full-vue.txt` | Working in a Vue project |
| `llms-full-vanilla.txt` | Plain TypeScript / JavaScript, no framework |
| `llms-full.txt` | Framework unknown, or multiple frameworks in one session |

All variants are ~900 kB–1.2 MB. If your tool cannot fetch or fully process the file in one pass:

1. Download the right variant once: `curl -L https://toolboxjs.com/llms-full-angular.txt -o llms-full-angular.txt`
2. Search for the topic: `rg -n 'your keyword' llms-full-angular.txt`
3. Extract the matching region: `sed -n '1200,1320p' llms-full-angular.txt`
4. Paste only those slices into context — not the whole file.

**Keep the local copy fresh.** These files are regenerated on every docs build. A cached copy older than one week may reference stale API, wrong import paths, or removed features. Re-download before starting any significant implementation work.

Preferred retrieval order (smallest to largest): per-page `.md` companion (e.g. `/grid/plugins/editing.md`) → `llms.txt` index → framework-scoped `llms-full-{framework}.txt` local-grepped slices → `llms-full.txt` local-grepped slices.

Because this introduction always sorts first in the corpus, you are reading these instructions even if your context window is smaller than the full file.

## RULE 0 (HIGHEST PRIORITY) — Prefer a single `gridConfig` over fragmented props

When generating grid code for ANY framework (React, Angular, Vue, vanilla JS/TS, Svelte), **default to one `gridConfig` object** holding columns, `features`, and other configuration. Reserve framework props for reactive data (`rows`) and the imperative `ref`/handle. Do NOT spread configuration across many individual props/inputs/attributes unless the user explicitly asks.

WHY: one object describes the whole grid, is portable across frameworks (the same `GridConfig` works in vanilla, React, Angular, Vue), and keeps multi-line config (callbacks like `groupOn`, `dataSource`, renderers) readable.

```ts
const gridConfig: GridConfig<Employee> = {
  columns: [/* … */],
  features: { selection: 'range', editing: 'dblclick' },
};
```

- **React:**   `<DataGrid rows={data} gridConfig={gridConfig} />` (memoize with `useMemo`)
- **Angular:** `<tbw-grid [rows]="data" [gridConfig]="gridConfig" />`
- **Vue:**     `<TbwGrid :rows="data" :grid-config="gridConfig" />` (wrap with `markRaw()`)
- **Vanilla:** `const grid = createGrid<Employee>(gridConfig); grid.rows = data;`

Individual feature props (`<DataGrid selection="row" />`) remain fully supported — use them ONLY for very small grids (≤ 2 features, each a boolean/short string) or when explicitly requested.

## RULE 0.1 — Framework adapters must use framework-native renderers/editors

When the user is inside **React/Vue/Angular**, treat framework-native renderer/editor APIs as default best practice:

- **React:** JSX/component renderers/editors
- **Vue:** slot/component renderers/editors
- **Angular:** `*tbwRenderer`, template/component renderers/editors

Do **not** default to plain `HTMLElement` renderer/editor functions in adapter code unless the user explicitly asks for framework-agnostic/vanilla output.

## RULE 0.2 — Prefer features, not manual plugin instances

Default to `gridConfig.features` + side-effect feature imports. Treat manual plugin instantiation (`plugins: [new SelectionPlugin()]`) as an advanced exception, primarily for custom plugin development or narrowly-scoped imperative cases.

If imperative access is needed after initialization, prefer `grid.getPluginByName('...')` over storing manually-created plugin instances in application code.

## CRITICAL RULES — read before generating any code

These apply to ALL frameworks. Violating them produces broken grids.

1. **Side-effect imports are always required.** `gridConfig.features.X` (or a feature prop) does NOT remove the need to import the feature factory — without the import the merge produces no plugin:
   ```ts
   import '@toolbox-web/grid/features/selection';        // vanilla / any framework
   import '@toolbox-web/grid-react/features/selection';  // or the adapter path
   ```
   Vanilla JS must also register the element itself: `import '@toolbox-web/grid';` (adapters auto-import it).
2. **Height is required.** The grid needs an explicit height or it renders at zero height: `tbw-grid { height: 400px; }`. (`display: block` is set automatically — do not add it.)
3. **Editing is opt-in.** `editable: true` on a column WITHOUT the editing feature/plugin throws. Load `@toolbox-web/grid/features/editing` and set `features: { editing: true }`.
4. **Plugin load order matters when using plugin API directly.** `ClipboardPlugin` requires `SelectionPlugin`; `UndoRedoPlugin` requires `EditingPlugin` — load the dependency first. Prefer `features` so ordering/dependencies are handled automatically.
5. **Some plugins are mutually exclusive.** `GroupingRows` ✗ `Tree` ✗ `Pivot` (all rewrite the row model); `ServerSide` ✗ `Pivot`. A dev-mode warning fires on conflict. (`ServerSide` + `Tree` and `ServerSide` + `GroupingRows` DO coexist.)
6. **Light DOM, no Shadow DOM.** CSS cascade works normally — no `::part()`/`::slotted()`.
7. **Em-based sizing.** All dimensions use `em`; scale the whole grid by changing `font-size` on `tbw-grid`.
8. **Type import:** `import type { DataGridElement } from '@toolbox-web/grid';` (the old `GridElement` alias is deprecated).

## ANTI-PATTERNS — don't reach for a plugin first

- **Don't add `SelectionPlugin` just to make a row clickable.** For "click row → open detail", listen for `cell-activate` (fires for pointer AND keyboard, so it's accessible for free). Add `SelectionPlugin` only for persistent visible selection state, checkboxes, or multi-select.
- **Don't write `cell-click`/`row-click` when you mean "activate".** Those are pointer-only — keyboard users won't trigger them. `cell-activate` is the unified, cancelable activation event. Use `cell-click` only when you specifically need pointer-only behaviour (e.g. left-vs-right button).
- **Don't subclass `BaseGridEditor` before trying `column.type`.** Built-in types (`'select'`, `'number'`, `'date'`, …) plus `gridConfig.typeDefaults` cover most editor needs. Subclass only for genuinely custom editor UI.
- **Don't reinvent post-render orchestration.** To act after first render (focus a cell, scroll to row, begin an edit), `await grid.ready()` instead of chaining `setTimeout`/`requestAnimationFrame`/`afterNextRender`.

A **high-performance, framework-agnostic data grid** web component built with pure TypeScript. No runtime dependencies—just drop it into any project and start rendering data.

## Quick Start

The grid ships as a standard custom element. Pick the install style that matches your setup.

#### With a bundler (Vite, webpack, etc.)

```bash
npm install @toolbox-web/grid
```

```typescript title="main.ts"
import '@toolbox-web/grid';
import { queryGrid } from '@toolbox-web/grid';

const grid = queryGrid('tbw-grid');
grid.columns = [
  { field: 'id', header: 'ID', type: 'number', sortable: true },
  { field: 'name', header: 'Name', sortable: true },
  { field: 'email', header: 'Email' },
];
grid.rows = [
  { id: 1, name: 'Alice', email: 'alice@example.com' },
  { id: 2, name: 'Bob',   email: 'bob@example.com' },
  { id: 3, name: 'Carol', email: 'carol@example.com' },
];
```

```html title="index.html"
<tbw-grid style="height: 300px;"></tbw-grid>
```

#### No build (CDN, single HTML file)

Drop one `<script>` tag and you're done — no bundler, no install. Everything is exposed on the global `TbwGrid` object.

```html title="index.html"
<!DOCTYPE html>
<script src="https://unpkg.com/@toolbox-web/grid/umd/grid.umd.js"></script>

<tbw-grid id="my-grid" style="height: 300px;"></tbw-grid>

<script>
  const grid = TbwGrid.queryGrid('#my-grid');
  grid.columns = [
    { field: 'id', header: 'ID', type: 'number', sortable: true },
    { field: 'name', header: 'Name', sortable: true },
    { field: 'email', header: 'Email' },
  ];
  grid.rows = [
    { id: 1, name: 'Alice', email: 'alice@example.com' },
    { id: 2, name: 'Bob',   email: 'bob@example.com' },
    { id: 3, name: 'Carol', email: 'carol@example.com' },
  ];
</script>
```

See the [Getting Started guide](/grid/getting-started.md) for framework integration (React, Vue, Angular), declarative HTML, plugins, and TypeScript setup.

### Live Demo

```ts
// IntroBasicDemo.astro
  import '@toolbox-web/grid';
import { queryGrid } from '@toolbox-web/grid';

  const grid = queryGrid('#demo-intro-basic');
  if (grid) {
    grid.columns = [
      { field: 'id', header: 'ID', type: 'number', sortable: true },
      { field: 'name', header: 'Name', sortable: true },
      { field: 'email', header: 'Email' },
    ];
    grid.rows = [
      { id: 1, name: 'Alice', email: 'alice@example.com' },
      { id: 2, name: 'Bob', email: 'bob@example.com' },
      { id: 3, name: 'Carol', email: 'carol@example.com' },
      { id: 4, name: 'Dan', email: 'dan@example.com' },
      { id: 5, name: 'Eve', email: 'eve@example.com' },
    ];
  }
```

## Architecture Highlights

Under the hood, the grid employs patterns typically found in enterprise-grade solutions:

| Pattern | What It Does |
| ------- | ------------ |
| **Centralized Render Scheduler** | Batches all updates into a single `requestAnimationFrame` per frame—no layout thrashing |
| **Phase-Based Execution** | Prioritizes work (config → rows → columns → render) for predictable updates |
| **DOM Recycling** | Reuses row elements via a pool with epoch-based invalidation—minimal GC pressure |
| **Template Cloning** | Pre-created templates cloned via `cloneNode(true)`—3-4x faster than `createElement` |
| **Event Delegation** | Single listener per event type on the container—scales to any dataset size |
| **Faux Scrollbar** | Separates scroll container from content—no reflow during scroll |

Read the full [Architecture deep-dive](/grid/architecture.md) for implementation details.

## Plugin System

The core grid is intentionally minimal. Advanced features are delivered through tree-shakeable plugins — import only what you need:

- **SelectionPlugin** — Cell, row, or range selection
- **FilteringPlugin** — Column header filters with custom panels
- **EditingPlugin** — Inline editing with built-in and custom editors
- **GroupingRowsPlugin** — Hierarchical row grouping with aggregations
- **TreePlugin** — Expandable tree data with lazy loading
- **MasterDetailPlugin** — Expandable detail rows
- **ExportPlugin** — CSV, Excel, or JSON export
- **ClipboardPlugin** — Copy/paste with Excel-compatible formatting
- ...and [many more](/grid/plugins.md)

Plugins benefit from **dependency validation**, **type-safe config extension**, **auto-cleanup** via `AbortSignal`, and a **third-party friendly** API so you can [build and distribute your own](/grid/plugin-development/custom-plugins.md).

## Next Steps

Ready to dive in?

  - [Getting Started](/grid/getting-started.md): Detailed setup for Vanilla JS, React, Vue, and Angular
  - [Core Features](/grid/core.md): Sorting, rendering, keyboard navigation, and interactive playground
  - [Plugins](/grid/plugins.md): Extend with selection, filtering, grouping, and 24+ more
  - [API Reference](/grid/api-reference.md): Complete property, method, and event reference

---
