هذه الصفحة غير مترجمة بعد، وهي معروضة بالإنجليزية.

Theming slotsmith means setting CSS custom properties. The stylesheet reads eleven shared --ss-* tokens, so a few values restyle all four components at once; a ready-made theme sets the same tokens for you. Without the stylesheet, you style the parts yourself, with plain CSS, Tailwind or a design system.

Tokens

Set the tokens on :root, in a stylesheet loaded after slotsmith’s:

/* After slotsmith's stylesheet: one --ss-* value restyles all four components. */
:root {
  --ss-accent: #7c3aed;
  --ss-radius: 12px;
}

/* A value on :root applies to both palettes, so give the dark one its own. */
.dark,
[data-theme="dark"] {
  --ss-accent: #a78bfa;
}

That restyles the whole page. Set them on any other element instead, such as a wrapper around one section, to restyle only the components inside it.

Token What it colours or sizes
--ss-surface The background of every component and popup
--ss-text Text
--ss-muted Secondary text: placeholders, captions, counters
--ss-border Borders and dividers, and the autocomplete list’s thin scrollbar
--ss-accent Focus rings, checkboxes, the picked day, tags, upload progress and the drop zone while a file is dragged over it
--ss-on-accent Text on the accent. Only the date picker reads it, for the picked day
--ss-danger Errors: the error rows, a rejected file, and the border and focus ring of an invalid autocomplete or date picker
--ss-hover The background of a hovered row, option, day or button
--ss-selected The background of a selected row. Only the data table reads it
--ss-radius Corner radius
--ss-font-size Base font size

Each component also has its own tokens, which fall back to the shared ones: --sdt-* for the data table, --sac-* for the autocomplete, --sdp-* for the date picker and --sfu-* for the file uploader. Set one of those to restyle one component without the others; it beats the shared token wherever each is set, so a --sdt-accent on :root beats a --ss-accent on a closer wrapper. The date picker and the uploader also follow a theme written against the data table’s --sdt-* when no --ss-* value is set for the same thing. The danger colour has a component token in each too, such as --sdp-danger for the date picker’s invalid state. Each component’s API page lists its tokens.

The colour, radius and font-size component tokens are inputs only: the stylesheet does not declare them, so var(--sdt-accent) in your own CSS is empty unless you set it. Read var(--ss-accent, <default>) instead. The few tokens with no shared counterpart do have defaults on :root: the table’s --sdt-stripe, --sdt-skeleton-bg, --sdt-skeleton-bg-2 and --sdt-max-height, and the sizes --sdp-cell, --sdp-gap, --sfu-gap and --sfu-tile-size. Set a component token on the component or an element above it; one set on an inner part, such as .sdt__row, is not read. A popup rendered outside the wrapper, such as one portalled to document.body, does not see the wrapper’s --ss-* and takes the page’s values instead.

Themes

Six themes ship with the library: minimal, soft, ocean, forest, sunset and contrast, a high-contrast palette. Each sets only the shared tokens, with a light and a dark palette. Pick one to try it here; the rest of this page keeps its look:

Theme
Things Fall Apart1958
Season of Migration to the North1966
Beloved1987

Import a theme after the stylesheet:

// After the stylesheet, so the theme's tokens win over the defaults.
import "slotsmith/styles.css";
import "slotsmith/themes/soft.css";

A theme sets its tokens on the same selectors as your own overrides, so the import order decides: import your overrides after the theme to keep them. To write your own theme, set only the shared tokens, on :root and again for dark mode, as in Tokens.

Dark mode

The stylesheet and every theme switch to their dark palette under .dark or [data-theme="dark"], set on <html> or on any element above the components. Most dark-mode setups already set one of the two, so the components follow with no further code. A token you set on :root applies to both palettes, so give its dark value under the same two selectors.

An app that follows the system setting, with no class to toggle, sets the dark values itself in a media query:

/* The stylesheet and every theme switch to dark under .dark or [data-theme="dark"],
   on <html> or on any element above the components. Nothing else is needed.

   An app that follows the system setting instead, with no class to toggle,
   sets the dark values itself. These are the stylesheet's own: */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --ss-surface: #141416;
    --ss-text: #f5f5f5;
    --ss-muted: #a3a3a3;
    --ss-border: #2a2a2a;
    --ss-accent: #60a5fa;
    --ss-on-accent: #0b0b0c;
    --ss-danger: #f87171;
    --ss-hover: rgb(255 255 255 / 6%);
    --ss-selected: rgb(96 165 250 / 12%);
  }
}

The table’s stripes and loading skeletons have no shared token and keep their light colours in that setup; set --sdt-stripe, --sdt-skeleton-bg and --sdt-skeleton-bg-2 too if you use them.

Tailwind

Tailwind is not needed: the stylesheet is plain CSS. With Tailwind there are two ways.

  • Keep the stylesheet and point the tokens at your theme: Tailwind 4 exposes its colours as CSS variables, so --ss-accent: var(--color-violet-600) works on :root.
  • Drop the stylesheet and give the parts Tailwind classes. Each element part is a plain element you can replace, and its state is a data-* attribute Tailwind can select:
import {
  DataTable,
  type CellSlotProps,
  type DataTableColumnDef,
  type HeaderCellSlotProps,
  type RowSlotProps,
  type TableSlotProps,
} from "slotsmith/data-table";

type Book = { id: string; title: string; year: number };

const columns: DataTableColumnDef<Book>[] = [
  { accessorKey: "title", header: "Title" },
  { accessorKey: "year", header: "Year" },
];

// No slotsmith stylesheet: each element part is your own element with Tailwind
// classes. A selected row carries data-state="selected".
const Table = (props: TableSlotProps) => <table {...props} className="w-full text-sm" />;
const Row = (props: RowSlotProps) => <tr {...props} className="border-b border-zinc-200 data-[state=selected]:bg-violet-50" />;
const HeaderCell = (props: HeaderCellSlotProps) => <th {...props} className="px-3 py-2 text-start font-medium text-zinc-500" />;
const Cell = (props: CellSlotProps) => <td {...props} className="px-3 py-2" />;

export function Books({ books }: { books: Book[] }) {
  return <DataTable data={books} columns={columns} components={{ Table, Row, HeaderCell, Cell }} />;
}

The shadcn/ui adapters do this for every part; see the data table’s adapters.

Own styles

Without any slotsmith stylesheet, style the built-in parts by their class names. Every component names them the same way: s plus its initials (sdt, sac, sdp, sfu), then __part, then --modifier, with state in data-* attributes. A part with the same role has the same name in each component: the popups are __popup, an empty state is __message, an error state __error.

/* No slotsmith stylesheet: style the built-in parts by their class names.
   Classes are s + the component's initials, __part, --modifier; state is in data-*. */
.sdt__table {
  width: 100%;
  border-collapse: collapse;
}

.sdt__cell {
  padding: 0.5rem 0.75rem;
  border-block-end: 1px solid #e4e4e7;
  text-align: start;
}

.sdt__row[data-state="selected"] {
  background: #f5f3ff;
}

/* A part with the same role has the same name in every component. */
.sac__popup,
.sdp__popup {
  border: 1px solid #e4e4e7;
  background: #ffffff;
}

Each component’s API page lists its classes under Styling.

RTL

The stylesheets use logical properties only, such as margin-inline-start and inset-inline-end, so every component mirrors when its page or a wrapper is dir="rtl". The components follow the CSS direction around them; the locale does not set it. Inside SlotsmithProvider, useSlotsmithLocale() returns the active locale’s tag and direction:

import type { ReactNode } from "react";
import { useSlotsmithLocale } from "slotsmith/provider";

// The components follow the CSS direction of the page around them. Inside the
// provider, take it from the active locale: ar, fa and he are right to left.
export function Direction({ children }: { children: ReactNode }) {
  const { code, dir } = useSlotsmithLocale();
  return (
    <div lang={code} dir={dir}>
      {children}
    </div>
  );
}

On a right-to-left page the date picker also points its previous and next month arrows the other way. Languages lists the right-to-left packs.