A reactive Svelte 5 wrapper for AG Grid with full TypeScript support.
- Simple, reactive API
- Fully typed using AG Grid's types
- Reactive updates for rowData, columnDefs, and more
- Minimal wrapper - AG Grid does the heavy lifting
- Flexible module system support
npm install svelte-ag-grid ag-grid-community @ag-grid-community/stylespnpm add svelte-ag-grid ag-grid-community @ag-grid-community/stylesbun add svelte-ag-grid ag-grid-community @ag-grid-community/styles<script lang="ts">
import { AgGrid, ModuleRegistry, AllCommunityModule } from 'svelte-ag-grid';
// Register AG Grid modules (required)
ModuleRegistry.registerModules([AllCommunityModule]);
const rowData = [
{ make: 'Toyota', model: 'Celica', price: 35000 },
{ make: 'Ford', model: 'Mondeo', price: 32000 },
{ make: 'Porsche', model: 'Boxster', price: 72000 }
];
const columnDefs = [
{ field: 'make' },
{ field: 'model' },
{ field: 'price' }
];
</script>
<div style="height: 400px;">
<!-- Direct props (recommended) -->
<AgGrid {rowData} {columnDefs} />
<!-- Or spread an options object -->
<!-- <AgGrid {...gridOptions} /> -->
</div>The AgGrid component accepts props in three flexible ways:
<AgGrid
rowData={myData}
columnDefs={columns}
pagination={true}
paginationPageSize={20}
defaultColDef={{ sortable: true }}
/><script lang="ts">
const gridOptions = {
rowData: myData,
columnDefs: columns,
pagination: true,
paginationPageSize: 20
};
</script>
<AgGrid {...gridOptions} /><AgGrid
{...baseGridOptions}
rowData={dynamicData}
pagination={showPagination}
/>Note: Direct props take precedence over spread options when both are provided.
AG Grid uses a modular architecture. You have several options:
import { ModuleRegistry, AllCommunityModule } from 'svelte-ag-grid';
ModuleRegistry.registerModules([AllCommunityModule]);import { ModuleRegistry } from 'svelte-ag-grid';
import { ClientSideRowModelModule } from 'ag-grid-community';
import { CsvExportModule } from 'ag-grid-community';
ModuleRegistry.registerModules([ClientSideRowModelModule, CsvExportModule]);<script>
import { AgGrid } from 'svelte-ag-grid';
import { ClientSideRowModelModule, CsvExportModule } from 'ag-grid-community';
import type { GridParams } from 'svelte-ag-grid';
const params: GridParams = {
modules: [ClientSideRowModelModule, CsvExportModule]
};
</script>
<AgGrid rowData={data} columnDefs={cols} {params} />The component automatically watches and updates these properties:
rowDatacolumnDefsdefaultColDefpaginationpaginationPageSize
<script lang="ts">
let rowData = $state([...]);
// This will automatically update the grid
function addRow() {
rowData = [...rowData, { make: 'BMW', model: 'M3', price: 65000 }];
}
</script>The AgGrid component accepts all AG Grid options as direct props, plus:
| Prop | Type | Default | Description |
|---|---|---|---|
params |
GridParams |
{} |
Grid creation parameters |
api |
GridApi |
- | Bindable grid API |
All AG Grid options can be passed as props (e.g., rowData, columnDefs, pagination, etc.)
All AG Grid options are available as properly typed props. For wrapper components, you have two type options:
Option 1: Clean Types (No Snippets)
import type { AgGridProps } from 'svelte-ag-grid';
// Simple wrapper without snippet support
interface MyGridProps<T> extends Partial<AgGridProps<T>> {
data: T[];
title?: string;
}Option 2: Full Types (With Snippets)
import type { AgGridPropsWithSnippets } from 'svelte-ag-grid';
// Wrapper that supports snippet pass-through
interface MyGridProps<T> extends Partial<AgGridPropsWithSnippets<T>> {
data: T[];
title?: string;
}Example wrapper with snippet support:
<!-- MyGrid.svelte -->
<script lang="ts" generics="T">
import { AgGrid, type AgGridPropsWithSnippets } from 'svelte-ag-grid';
interface Props extends Partial<AgGridPropsWithSnippets<T>> {
data: T[];
title?: string;
}
let { data, title, ...gridProps }: Props = $props();
const defaults = {
pagination: true,
paginationPageSize: 20,
defaultColDef: { sortable: true, filter: true }
};
</script>
<h2>{title}</h2>
<AgGrid {...defaults} {...gridProps} rowData={data}>
{@render children?.()}
</AgGrid>Then use with snippets:
<MyGrid {data} title="My Data" columnDefs={cols}>
{#snippet score(props)}
<span class="score">{props.params.value}</span>
{/snippet}
{#snippet name(props)}
<strong>{props.params.value}</strong>
{/snippet}
</MyGrid>When using both spread syntax and direct props:
<AgGrid
{...baseOptions} <!-- Applied first -->
rowData={dynamicData} <!-- Overrides baseOptions.rowData -->
pagination={true} <!-- Overrides baseOptions.pagination -->
/>Direct props take precedence over spread options, allowing you to override specific values while keeping defaults.
This library provides three ways to create custom cell renderers:
The easiest and most powerful way is to use inline snippets directly inside the <AgGrid> component. Simply define snippets with names matching your column field names:
<script lang="ts">
import { AgGrid } from 'svelte-ag-grid';
import type { GridOptions } from 'ag-grid-community';
interface Person {
name: string;
age: number;
score: number;
status: 'active' | 'inactive';
}
const columnDefs = [
{ field: 'name', headerName: 'Name' },
{ field: 'age', headerName: 'Age' },
{ field: 'score', headerName: 'Score' }, // Will use score snippet
{ field: 'status', headerName: 'Status' } // Will use status snippet
];
const rowData: Person[] = [
{ name: 'Alice', age: 25, score: 95, status: 'active' },
{ name: 'Bob', age: 30, score: 87, status: 'inactive' },
{ name: 'Charlie', age: 35, score: 92, status: 'active' }
];
</script>
<div style="height: 400px;">
<AgGrid {rowData} {columnDefs}>
<!-- Snippet name must match column field name -->
{#snippet score(props)}
<div class="score-cell">
<span
class="score-value {props.params.value >= 90 ? 'excellent' : props.params.value >= 80 ? 'good' : 'okay'}"
>
{props.params.value}
</span>
<div class="score-bar">
<div class="score-fill" style="width: {props.params.value}%"></div>
</div>
</div>
{/snippet} {#snippet status(props)}
<span class="status-badge {props.params.value}"> {props.params.value} </span>
{/snippet}
</AgGrid>
</div>
<style>
:global(.score-cell) {
display: flex;
align-items: center;
gap: 0.5rem;
}
:global(.score-value.excellent) {
color: #16a34a;
}
:global(.score-value.good) {
color: #2563eb;
}
:global(.score-value.okay) {
color: #ea580c;
}
:global(.score-bar) {
flex: 1;
height: 4px;
background-color: #e5e7eb;
border-radius: 2px;
overflow: hidden;
}
:global(.score-fill) {
height: 100%;
background: linear-gradient(90deg, #ea580c 0%, #2563eb 50%, #16a34a 100%);
transition: width 0.3s ease;
}
:global(.status-badge) {
padding: 0.25rem 0.5rem;
border-radius: 0.25rem;
font-size: 0.75rem;
text-transform: uppercase;
}
:global(.status-badge.active) {
background-color: #dcfce7;
color: #166534;
}
:global(.status-badge.inactive) {
background-color: #fef2f2;
color: #991b1b;
}
</style>Benefits of inline snippets:
- β Fully type-safe - snippet names must match field names
- β No manual cell renderer setup required
- β Clean, declarative syntax
- β Automatic integration with AG Grid
Important Notes:
- Snippet names must match your column field names exactly
- Field names that conflict with component props (
options,params,api) cannot be used as snippet names - Snippets receive
props.paramscontaining AG Grid'sICellRendererParams
Use makeSvelteSnippetRenderer for snippets defined outside the grid:
<script lang="ts">
import { AgGrid, makeSvelteSnippetRenderer } from 'svelte-ag-grid';
const columnDefs = [
{ field: 'name' },
{
field: 'price',
cellRenderer: makeSvelteSnippetRenderer(priceCell, (params) => ({
price: params.value
}))
}
];
const rowData = [
{ name: 'Product A', price: 99.99 },
{ name: 'Product B', price: 149.99 }
];
</script>
{#snippet priceCell(params: { price: number })}
<span class="price {params.price > 100 ? 'expensive' : 'affordable'}">
${params.price.toFixed(2)}
</span>
{/snippet}
<AgGrid {rowData} {columnDefs} />Use makeSvelteCellRenderer for reusable Svelte components:
<script lang="ts">
import { AgGrid, makeSvelteCellRenderer } from 'svelte-ag-grid';
import MyButton from './MyButton.svelte';
const ButtonRenderer = makeSvelteCellRenderer(MyButton, (params) => ({
label: params.value,
onclick: () => console.log('Clicked:', params.data)
}));
const columnDefs = [
{ field: 'name' },
{
field: 'action',
cellRenderer: ButtonRenderer
}
];
const rowData = [
{ name: 'Item 1', action: 'Edit' },
{ name: 'Item 2', action: 'Delete' }
];
</script>
<AgGrid {rowData} {columnDefs} />Both renderers require a props transformer function that converts AG Grid's ICellRendererParams into the props your component or snippet expects:
// The transformer receives AG Grid cell parameters
(params: ICellRendererParams) => {
return {
// Transform to your component's expected props
value: params.value,
data: params.data,
isSelected: params.node.isSelected(),
// Add any custom logic
displayValue: params.value > 100 ? 'High' : 'Low'
};
};For full AG Grid configuration options and features, see the official documentation: https://www.ag-grid.com/javascript-data-grid/