A reactive Svelte 5 wrapper for AG Grid with full TypeScript support.
npm install svelte-ag-grid ag-grid-community @ag-grid-community/styles
pnpm add svelte-ag-grid ag-grid-community @ag-grid-community/styles
bun 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:
rowData
columnDefs
defaultColDef
pagination
paginationPageSize
<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:
Important Notes:
options
, params
, api
) cannot be used as snippet namesprops.params
containing AG Grid's ICellRendererParams
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/