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:
npm install @kobalte/core @tanstack/solid-table clsx tailwind-merge lucide-solid
And:
dotnet add package Partas.Solid.TanStack.Tabledotnet add package Partas.Solid.Lucidedotnet add package Partas.Solid.Kobalte
Spin-up the dev server and make sure everything is working as expected:
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:
{ "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.
npm install
Install the following packages (and also install Fable 5.0+):
dotnet add package Partas.Soliddotnet add package Partas.Solid.TanStack.Tabledotnet add package Partas.Solid.Kobaltedotnet add package Partas.Solid.Lucide
paket install Partas.Solidpaket install Partas.Solid.TanStack.Tablepaket install Partas.Solid.Kobaltepaket 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:
// Remember your namespaces must start with Partas.Solidmodule Partas.Solid.Example.Rootopen Partas.Solidopen Fable.Core
[<SolidComponent>]let Root () = div() { "Hello World!" }
Now add the following to your Program.fs
module Partas.Solid.Example.Program
open Partas.Solid.Example.Rootopen Partas.Solidopen Fable.Coreopen 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!"
npm run start
Last updated: 7/13/25, 12:35 PM