@mediakular/gridcraft
is a powerful data grid package made for Svelte applications.
We focus on making GridCraft as easy to use and customize as possible for developers, while still providing all the features a modern grid requires.
The Grid can be used in a variety of ways - from very simple tables to feature-rich grids with grouping, selecting, sorting, custom columns and more. It was important to us to keep the number of dependencies as well as the file size to a minimum. That's why GridCraft feels easy to use and doesn't interfere with your code.
The component is lightning fast and integrates into your project super quickly.
Here are some screenshots of the default themes. These themes are fully customizable and you can also create your own themes in a snap.
- Paging: Use the default paging component or create your own.
- Sorting: Use default sorting, set specific sorting value or implement your own custom sorting function.
- Filtering: Implement your own filters - quick and simple.
- Grouping: It's never been easier to set up grouping functionality for your grid.
- Row Selection: Row selection made easy - juist activate it and access selected rows.
- Custom Row edit: Simply create your own column with with your own actions/functions. You can also integrate any third-party components to edit your data.
- Theming: Personalize grid appearance to match your style guide. Overwrite existing default themes or create your own. There are endless possibilities and we tried to make it as easy as possible for you.
- Typesafe: Stay typesafe and use the types from your own business model.
- Tailwind CSS Ready: Completely compatible with Tailwind CSS and any other CSS framework.
npm install @mediakular/gridcraft
or
yarn add @mediakular/gridcraft
or
pnpm add @mediakular/gridcraft
or
bun add @mediakular/gridcraft
Most basic usage. In this example GridCraft will automatically detect the properties of type Client
and generate a column for each property.
<script lang="ts">
import { Grid } from '@mediakular/gridcraft';
import { clients } from './clients.js'; // [{name: ..., age: ..., ...}, {}, {}]
</script>
<Grid data={clients} />
Here an example with a simple custom column definition.
<script lang="ts">
import { Grid, type GridColumn } from "@mediakular/gridcraft";
import { clients } from './clients.js';
interface Client {
id: string;
firstname: string;
lastname: string;
age: number;
birthdate: Date;
}
let columns: GridColumn<Client>[] = [
{
key: 'firstname',
title: 'First Name'
},
{
key: 'lastname',
title: 'Last Name'
},
{
key: 'age',
title: 'Age'
},
{
key: 'birthdate',
title: 'Birthday'
}
];
</script>
<Grid
data={clients}
{columns} />
GridCraft allows you to simply define your own custom svelte components to render column cells.
The following example shows you how to define a custom renderComponent
:
<script lang="ts">
import { Grid, type GridColumn } from "@mediakular/gridcraft";
import { clients } from './clients.js';
import ClientCell from "$lib/components/grid/cells/ClientCell.svelte";
import CurrencyCell from "$lib/components/grid/cells/CurrencyCell.svelte";
import DateCell from "$lib/components/grid/cells/DateCell.svelte";
interface Client {
id: string;
firstname: string;
lastname: string;
avatar: string;
email: string;
age: number;
birthdate: Date;
amount: number;
quantity: number;
}
let columns: GridColumn<Client>[] = [
{
key: 'name',
title: 'Name',
// Use an accessor to transform row data, which can be used in your custom renderComponent
accessor: (row: Client) => {
return {
avatar: row.avatar,
firstname: row.firstname,
lastname: row.lastname,
email: row.email
}
},
// as the default search will not work with our accessor data, we have to provide a sortValue which will be used for sorting
sortValue: (row: Client) => {
return `${row.firstname} ${row.lastname}`
},
renderComponent: ClientCell // Our custom column cell component to render a column with avatar, full name and email
},
{
key: 'age',
title: 'Age'
},
{
key: 'birthdate',
title: 'Birthday',
renderComponent: DateCell // Our custom column cell component to render a formatted date
},
{
key: 'total',
title: 'Total',
accessor: (row: Client) => { return row.amount * row.quantity },
renderComponent: CurrencyCell // Our custom column cell component to render a calculated cell and formatted currency
},
];
</script>
<Grid
data={clients}
bind:columns />
Here are the custom cell components used in the example above:
ClientCell.svelte
<script lang="ts">
export let avatar: string;
export let firstname: string;
export let lastname: string;
export let email: string;
let fullname = `${firstname} ${lastname}`;
</script>
<div class="my-client-cell">
<img src="{avatar}" alt="{fullname}" />
<div>
<span>{fullname}</span>
{#if email}
<span>{email}</span>
{/if}
</div>
</div>
DateCell.svelte
<script lang="ts">
export let value: Date;
let dateStr = value ? (new Date(value)).toLocaleDateString('en-US', { year: 'numeric', month: 'short', day: 'numeric' }) : "-";
</script>
<div>{dateStr}</div>
CurrencyCell.svelte
<script lang="ts">
export let value: number;
let currency = new Intl.NumberFormat("en-US", { currency: "USD", style: 'currency', 2, 0 }).format(value);
</script>
<div>{currency ? currency : '-'}</div>
Here an example on how to integrate a column with custom row actions. This could be used for example to display links or buttons to delete or edit a row, or to show row details.
<script lang="ts">
import { Grid, type GridColumn } from "@mediakular/gridcraft";
import ActionsCell from "$lib/components/grid/cells/ActionsCell.svelte";
import { clients } from './clients.js';
let columns: GridColumn<Client>[] = [
{
key: 'firstname',
title: 'First Name',
},
{
key: 'lastname',
title: 'Last Name',
},
{
key: 'email',
title: 'E-Mail',
},
{
key: 'actions', // you can call it however you like
title: 'Row Actions',
sortable: false,
accessor: (row: Client) => {
return {
row: row,
editClicked: (row: Client) => {
// Implement your edit function here. You can for example open a modal window which shows the edit form for the row
},
deleteClicked: (row: Client) => {
// Implement your delete function here. You can for example open a dialoge window here to confirm that the user wants to delete the row
},
somethingElseClicked: (row: Client) => {
// ...
}
}
},
renderComponent: ActionsCell
}
];
</script>
<Grid
data={clients}
{columns} />
ActionsCell.svelte
<script lang="ts">
type T = $$Generic<any>;
export let row: T;
export let editClicked: (row: T) => void;
export let deleteClicked: (row: T) => void;
export let somethingElseClicked: (row: T) => void;
function handleEditClick() {
editClicked(row);
}
function handleDeleteClick() {
deleteClicked(row);
}
function handleSomethingElseClick() {
somethingElseClicked(row);
}
</script>
<button on:click|preventDefault={handleEditClick}>
Edit
</button>
<button on:click|preventDefault={handleDeleteClick}>
Delete
</button>
<a href="#" on:click|preventDefault={handleSomethingElseClick}>
Something Else
</a>
Here a simple example with paging. If you are okay with the default values, you only need to define a variable of type PagingData
, which you need to set as attributes for the Grid
and GridFooter
components.
If you want to overwrite the defaults simply define them in the paging variable:
<script lang="ts">
import { Grid, PagingData, GridFooter, type GridColumn } from "@mediakular/gridcraft";
import { clients } from './clients.js';
let columns: GridColumn<Client>[] = [];
// Define paging variables, if you want to overwrite the default
let paging = new PagingData(1, 5, [5, 10, 20]);
// Or: let paging = new PagingData();
</script>
<Grid
data={clients}
{columns}
bind:paging />
<GridFooter bind:paging />
Simple paging example:
Custom paging example:
<script lang="ts">
import { Grid, type GridColumn } from "@mediakular/gridcraft";
import { clients } from './clients.js';
interface Client {
id: string;
firstname: string;
lastname: string;
age: number;
}
let groupBy = "";
let columns: GridColumn<Client>[] = [
{
key: 'firstname',
title: 'First Name',
},
{
key: 'lastname',
title: 'First Name',
},
{
key: 'age',
title: 'Age'
}
];
</script>
<!-- Just for demonstration purposes -->
<select bind:value={groupBy} >
<option value="">Select Column to Group By</option>
{#each columns as col (col.key)}
<option value={col.key}>{col.title}</option>
{/each}
</select>
<!-- End: Just for demonstration purposes -->
<Grid
bind:data={clients}
{columns}
bind:groupby />
<script lang="ts">
import { Grid, type GridColumn } from "@mediakular/gridcraft";
import { clients } from './clients.js';
interface Client {
id: string;
firstname: string;
lastname: string;
age: number;
}
let showCheckboxes = true;
let selectedRows:Client[] = [];
let columns: GridColumn<Client>[] = [
{
key: 'firstname',
title: 'First Name',
},
{
key: 'lastname',
title: 'First Name',
},
{
key: 'age',
title: 'Age'
},
];
</script>
<!-- Just for demonstration purposes -->
<label for="showCheckboxes">
<input type="checkbox" bind:checked={showCheckboxes} id="showCheckboxes"> Show checkboxes
</label>
{#if showCheckboxes}
Selected Rows:
<pre>
{JSON.stringify(selectedRows, null, 2)}
</pre>
{/if}
<!-- End: Just for demonstration purposes -->
<Grid
data={clients}
{columns}
{showCheckboxes}
bind:selectedRows />
<script lang="ts">
import { Grid, type GridColumn, type GridFilter } from "@mediakular/gridcraft";
import { clients } from './clients.js';
interface Client {
id: string;
firstname: string;
lastname: string;
age: number;
}
let textSearch = "";
let clientData = clients;
let filters: GridFilter[];
$: filters = [
{
key: "text-search", //can be chosen freely
columns: ["firstname", "lastname", "age"], // Define which columns you would like to use the filter for
filter: (row: any, colKey: string) => { // Actual filter function which will be called for each of the above defined columns. We return true for displaying the column and false for hiding it
const search = (val: string | null) => val != undefined && val.toString().toLocaleLowerCase().includes(textSearch.toLocaleLowerCase());
return search(row)
},
active: (textSearch && textSearch.length > 0) ? true : false // Here we return true when the filter should be active, when false the filter will be ignored
}
];
let columns: GridColumn<Client>[] = [
{
key: 'firstname',
title: 'Firstname',
},
{
key: 'lastname',
title: 'Lastname',
},
{
key: 'age',
title: 'Age'
},
];
</script>
<input type="text" placeholder="Enter Filter Term (Firstname, Lastname or Age)" bind:value={textSearch} />
<Grid
data={clientData}
{columns}
{filters} />
Example with text filter:
Example with checkbox filter:
Currently, gridcraft comes with three pre-defined themes: PlainTableCssTheme
, PlainTableTheme
and PrelineTheme
.
By default gridcraft uses PlainTableCssTheme
. While PlainTableCssTheme
is a fully styled theme and can be used as-is, PlainTableTheme
theme is a very basic table, without any styles or classes and serves mostly as a template for your own theme. You can copy PlainTableTheme
into your own project and transform it to fit your needs.
PrelineTheme
is inspired by preline.
There are currently three main components that can be themed: Grid
, GridFooter
and GridPaging
.
<script lang="ts">
import { Grid, type GridColumn, GridFooter, PrelineTheme, PlainTableCssTheme } from "@mediakular/gridcraft";
import { clients } from './clients.js';
let theme = PlainTableCssTheme;
let columns: GridColumn<Client>[] = [
...
];
</script>
<!-- Only for demonstration purposes -->
<button on:click={() => theme = PlainTableCssTheme}>Plain Css Theme</button>
<button on:click={() => theme = PrelineTheme}>Preline Theme</button>
<!-- End: Only for demonstration purposes -->
<Grid bind:data={clients} {columns} {theme} />
<GridFooter {theme}/>
When using PrelineTheme
you need to install tailwindcss and make sure to add this in your tailwind.config.js
:
export default {
content: [
...
'./node_modules/@mediakular/gridcraft/dist/themes/preline/**/*.svelte' // add this line
],
theme: {
...
},
plugins: [
...
],
}
This can be useful if you are satisfied with a certain theme, but you want to make only a few changes instead of creating a new custom theme.
<script lang="ts">
import { Grid, type GridColumn, GridFooter, PrelineTheme, PlainTableTheme } from "@mediakular/gridcraft";
import MyTableContainer from "$lib/components/grid/theme/MyTableContainer.svelte"
import { clients } from './clients.js';
let theme = PlainTableTheme;
theme.grid.container = MyTableContainer;
let columns: GridColumn<Client>[] = [
...
];
</script>
<Grid
bind:data={clients}
{columns}
{theme} />
<GridFooter {theme} />
MyTableContainer.svelte
<div class="my-custom-wrapper">
<table class="my-custom-table-class" id="custom-table-id">
<slot />
</table>
</div>
Find here the full theming documentation.
Here you can find the full documentation of GridCraft
Request new example codes which we can add in our documenatation: GitHub Discussion
New ideas you can post here so we can discuss them: GitHub Discussion
Here you can let us know about issues or bugs: GitHub Issues
Or ask the community in our Discord Channel
Support the development of GridCraft by becoming a sponsor:
Everyone is welcome to contribute to this project. Feel free to open an issue if you have question or found a bug.
Join the community in our Discord Channel. There you can ask everything to get started.
Follow us on Twitter
Sharing is appreciated. You've integrated GridCraft successfully in your project? - We would love to see it! Twitter it with mentioning @grid_craft or send us an email to gridcraft @ mediakular.com
Of course you can also share our website https://gridcraft.mediakular.com.
Grid API Column API Filter API
This package is licensed under the MIT License.