Skip to main content
Partas
warning

Due to an issue with module resolution, the styling for the current examples does not work on the website without tailwindcss. Rest assured the examples will be styled appropriately if you follow the guide.

Data Tables

With this example/guide, we're going to build a data table with @tanstack/solid-table using Partas.Solid.TanStack.Table, tailwindcss, and some other small utilities.

This example is sourced from the solid-ui implementation of shadcn-ui DataTables.

Getting Started

Either spin up an environment with Vite or Partas.SolidStart

Partas.SolidStart

See 'Getting Started'; spin-up a tailwind template.

Install the following dependencies:

Terminal window
npm install @kobalte/core @tanstack/solid-table clsx tailwind-merge lucide-solid

And:

Terminal window
dotnet add package Partas.Solid.TanStack.Table
dotnet add package Partas.Solid.Lucide
dotnet add package Partas.Solid.Kobalte

Spin-up the dev server and make sure everything is working as expected:

Terminal window
dotnet run dev

Vite

Create a console .fsproj and setup a vite environment within the project.

You can do this manually by creating a vite.config.mts, index.html, and index.css file with following settings:

Don't worry, we'll download the dependencies shortly

import { defineConfig } from 'vite'
import solidPlugin from 'vite-plugin-solid';
import tailwindcss from "@tailwindcss/vite";
// https://vitejs.dev/config/
export default defineConfig({
server: {
watch: {
ignored: [
"**/*.md" , // Don't watch markdown files
"**/*.fs" , // Don't watch F# files
"**/*.fsx" // Don't watch F# script files
]
}
},
plugins: [
solidPlugin(),
tailwindcss(),
],
})
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="icon" href="./favicon.ico" type="image/x-icon" />
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Partas.Solid Playground</title>
<script type="module" src="/Program.fs.jsx"></script>
<!--Adjust the src as required to point to your compiled entry file-->
</head>
<body>
<div id="root"></div>
</body>
</html>
@import 'tailwindcss';
/* set default border color due to tailwindcss v4 */
@layer base {
*,
::after,
::before,
::backdrop,
::file-selector-button {
border-color: var(--color-gray-200, currentColor);
}
}
/* Base color palette */
@layer base {
:root {
--background: hsl(0 0% 100%);
--foreground: hsl(240 10% 3.9%);
--muted: hsl(240 4.8% 95.9%);
--muted-foreground: hsl(240 3.8% 46.1%);
--popover: hsl(0 0% 100%);
--popover-foreground: hsl(240 10% 3.9%);
--border: hsl(240 5.9% 90%);
--input: hsl(240 5.9% 90%);
--card: hsl(0 0% 100%);
--card-foreground: hsl(240 10% 3.9%);
--primary: hsl(240 5.9% 10%);
--primary-foreground: hsl(0 0% 98%);
--secondary: hsl(240 4.8% 95.9%);
--secondary-foreground: hsl(240 5.9% 10%);
--accent: hsl(240 4.8% 95.9%);
--accent-foreground: hsl(240 5.9% 10%);
--destructive: hsl(0 84.2% 60.2%);
--destructive-foreground: hsl(0 0% 98%);
--info: hsl(204 94% 94%);
--info-foreground: hsl(199 89% 48%);
--success: hsl(149 80% 90%);
--success-foreground: hsl(160 84% 39%);
--warning: hsl(48 96% 89%);
--warning-foreground: hsl(25 95% 53%);
--error: hsl(0 93% 94%);
--error-foreground: hsl(0 84% 60%);
--ring: hsl(240 5.9% 10%);
--radius: 0.5rem;
}
.dark,
[data-kb-theme="dark"] {
--background: hsl(240 10% 3.9%);
--foreground: hsl(0 0% 98%);
--muted: hsl(240 3.7% 15.9%);
--muted-foreground: hsl(240 5% 64.9%);
--accent: hsl(240 3.7% 15.9%);
--accent-foreground: hsl(0 0% 98%);
--popover: hsl(240 10% 3.9%);
--popover-foreground: hsl(0 0% 98%);
--border: hsl(240 3.7% 15.9%);
--input: hsl(240 3.7% 15.9%);
--card: hsl(240 10% 3.9%);
--card-foreground: hsl(0 0% 98%);
--primary: hsl(0 0% 98%);
--primary-foreground: hsl(240 5.9% 10%);
--secondary: hsl(240 3.7% 15.9%);
--secondary-foreground: hsl(0 0% 98%);
--destructive: hsl(0 62.8% 30.6%);
--destructive-foreground: hsl(0 0% 98%);
--info: hsl(204 94% 94%);
--info-foreground: hsl(199 89% 48%);
--success: hsl(149 80% 90%);
--success-foreground: hsl(160 84% 39%);
--warning: hsl(48 96% 89%);
--warning-foreground: hsl(25 95% 53%);
--error: hsl(0 93% 94%);
--error-foreground: hsl(0 84% 60%);
--ring: hsl(240 4.9% 83.9%);
--radius: 0.5rem;
}
}
/* Sidebar colour palette */
@layer base {
:root {
--sidebar-background: hsl(0 0% 98%);
--sidebar-foreground: hsl(240 5.3% 26.1%);
--sidebar-primary: hsl(240 5.9% 10%);
--sidebar-primary-foreground: hsl(0 0% 98%);
--sidebar-accent: hsl(240 4.8% 95.9%);
--sidebar-accent-foreground: hsl(240 5.9% 10%);
--sidebar-border: hsl(220 13% 91%);
--sidebar-ring: hsl(217.2 91.2% 59.8%);
}
.dark,
[data-kb-theme="dark"] {
--sidebar-background: hsl(240 5.9% 10%);
--sidebar-foreground: hsl(240 4.8% 95.9%);
--sidebar-primary: hsl(224.3 76.3% 48%);
--sidebar-primary-foreground: hsl(0 0% 100%);
--sidebar-accent: hsl(240 3.7% 15.9%);
--sidebar-accent-foreground: hsl(240 4.8% 95.9%);
--sidebar-border: hsl(240 3.7% 15.9%);
--sidebar-ring: hsl(217.2 91.2% 59.8%);
}
}
@theme inline {
/* Color utils */
--color-border: var(--border);
--color-input: var(--input);
--color-ring: var(--ring);
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-primary: var(--primary);
--color-primary-foreground: var(--primary-foreground);
--color-secondary: var(--secondary);
--color-secondary-foreground: var(--secondary-foreground);
--color-destructive: var(--destructive);
--color-destructive-foreground: var(--destructive-foreground);
--color-muted: var(--muted);
--color-muted-foreground: var(--muted-foreground);
--color-info: var(--info);
--color-info-foreground: var(--info-foreground);
--color-success: var(--success);
--color-success-foreground: var(--success-foreground);
--color-warning: var(--warning);
--color-warning-foreground: var(--warning-foreground);
--color-error: var(--error);
--color-error-foreground: var(--error-foreground);
--color-accent: var(--accent);
--color-accent-foreground: var(--accent-foreground);
--color-popover: var(--popover);
--color-popover-foreground: var(--popover-foreground);
--color-card: var(--card);
--color-card-foreground: var(--card-foreground);
/* Sidebar */
--color-sidebar: var(--sidebar-background);
--color-sidebar-foreground: var(--sidebar-foreground);
--color-sidebar-primary: var(--sidebar-primary);
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
--color-sidebar-accent: var(--sidebar-accent);
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
--color-sidebar-border: var(--sidebar-border);
--color-sidebar-ring: var(--sidebar-ring);
/* Radius */
--border-radius-sm: calc(var(--radius) - 4px);
--border-radius-md: calc(var(--radius) - 2px);
--border-radius-lg: calc(var(--radius));
--border-radius-xl: calc(var(--radius) + 4px);
}

Here's a package.json file to match:

package.json
{
"private": "true",
"scripts": {
"start": "dotnet tool run fable watch -c Release --optimize --typedArrays false -e .fs.jsx --run vite",
},
"dependencies": {
"@kobalte/core": "^0.13.8",
"@tailwindcss/vite": "^4.0.1",
"@tanstack/solid-table": "^8.21.2",
"clsx": "^2.1.1",
"lucide-solid": "^0.474.0",
"solid-js": "^1.9.2",
"tailwind-merge": "^2.6.0",
"tailwindcss": "^4.0.1"
},
"devDependencies": {
"vite": "^5.4.9",
"vite-plugin-solid": "^2.10.2"
}
}

Make sure to install dependencies while you sort out dotnet dependencies.

Terminal window
npm install

Install the following packages (and also install Fable 5.0+):

dotnet add package Partas.Solid
dotnet add package Partas.Solid.TanStack.Table
dotnet add package Partas.Solid.Kobalte
dotnet add package Partas.Solid.Lucide
paket install Partas.Solid
paket install Partas.Solid.TanStack.Table
paket install Partas.Solid.Kobalte
paket install Partas.Solid.Lucide

This will give us some headless components, and icons to work with.

Now create a file that compiles before Program.fs called Root.fs.

Add the following:

Root.fs
// Remember your namespaces must start with Partas.Solid
module Partas.Solid.Example.Root
open Partas.Solid
open Fable.Core
[<SolidComponent>]
let Root () =
div() {
"Hello World!"
}

Now add the following to your Program.fs

Program.fs
module Partas.Solid.Example.Program
open Partas.Solid.Example.Root
open Partas.Solid
open Fable.Core
open Fable.Core.JsInterop
importSideEffects "./index.css"
render(Root, Browser.Dom.document.getElementById "root")

This should prevent any jankyness with the HMR. Now run npm script and see if you can load the browser with "Hello World!"

Terminal window
npm run start

Last updated: 7/13/25, 12:35 PM

PartasBuilt using the Partas.SolidStart SolidBase template
Community
githubdiscord