Skip to content
View as Markdown

Styling and Theming

Styling is done using Tailwind CSS v4. AppShell exports @tailor-platform/app-shell/styles, which includes the default palette and CSS variables.

To configure your application, import AppShell styles from your global CSS or top-level Tailwind CSS file:

css
@import "tailwindcss";
@import "@tailor-platform/app-shell/styles";

If you want a branded palette, import exactly one theme file after styles:

css
@import "tailwindcss";
@import "@tailor-platform/app-shell/styles";
@import "@tailor-platform/app-shell/themes/bloom";

After including this, your application's Tailwind utilities will resolve against the active AppShell tokens.

E.g.

tsx
<div className="text-muted-foreground bg-muted">...</div>

Note, many of these are default Tailwind colors, but there are some differences. If you omit this, much of the UI will look the same, but we will lose some of the Tailor-preferred colors.

Semantic color utilities

Beyond the standard shadcn/Tailwind names (background, muted, primary, …), AppShell bridges two semantic token families into Tailwind's color namespace, so they work with any color utility (bg-, text-, border-, ring-, …) and appear in editor autocomplete.

Status — flat colors, typically for badges and indicators:

Utility suffixToken
status-default--status-default
status-neutral--status-neutral
status-completed--status-completed
status-attention--status-attention
status-danger--status-danger
tsx
<span className="bg-status-attention">Pending review</span>

Alert — grouped sets for callouts, banners, and highlighted rows. Each of the five variants (neutral, success, warning, error, info) provides four slots:

SlotUtility exampleUse for
backgroundbg-alert-info-backgroundCallout fill
foregroundtext-alert-info-foregroundPrimary text and icons
foreground-mutedtext-alert-info-foreground-mutedSecondary/description text
borderborder-alert-info-borderCallout border
tsx
<div className="rounded-lg border px-4 py-3 bg-alert-info-background text-alert-info-foreground border-alert-info-border">
  <p className="font-medium">Heads up</p>
  <p className="text-alert-info-foreground-muted">
    This is the same palette the built-in Alert uses.
  </p>
</div>

These are the tokens the Alert component uses internally — reach for them when you need the same callout treatment somewhere Alert doesn't fit. All twenty resolve in both light and dark mode, and branded palettes inherit them from the default palette.

Prefer these named utilities over arbitrary-value syntax like bg-[color:var(--alert-info-background)]. Both produce identical CSS, but a typo in an arbitrary value fails silently — the element simply renders unstyled — whereas a misspelled utility class is caught by editor tooling.

Note that the background and border slots are already semi-transparent (a ~10% and ~20% tint respectively). An opacity modifier therefore compounds rather than replaces: bg-alert-info-background/50 yields roughly 5% alpha, not 50%. Set the background with an unmodified utility, or reach for the underlying accent color if you need a specific opacity.

A note on AppShell component class names

AppShell components use Tailwind utility classes for their styling. Tailwind classes are generated at build-time, so stylesheet for AppShell components is already built and is separate to the Tailwind stylesheet generated for your application.

In CSS, the order of style-definition affects the final styles which are computed for an element. Tailwind takes this into account when generating its stylesheet, however because it does not know that there's already a Tailwind-generated stylesheet included in the browser (AppShell's styles), there would be incorrect ordering of style definitions, and clashes can (though do not always) occur.

To avoid this situation, and to ensure correct style resolution, AppShell components use a class prefix "astw" (AppShell TailWind) to avoid clashes.

This is important to note for developing in AppShell.

Color Themes (Light / Dark / System)

AppShell supports three color modes: light, dark, and system (follows the OS setting).

Set the initial mode via the defaultColorTheme prop on <AppShell>. The user's selection is persisted to localStorage and restored on subsequent visits:

tsx
<AppShell defaultColorTheme="system" modules={modules}>
  {/* ... */}
</AppShell>

Use the useTheme hook to read or change the theme at runtime:

tsx
import { useTheme } from "@tailor-platform/app-shell";

function ThemeToggle() {
  const { theme, resolvedTheme, setTheme } = useTheme();
  return (
    <button onClick={() => setTheme(resolvedTheme === "dark" ? "light" : "dark")}>
      Switch to {resolvedTheme === "dark" ? "light" : "dark"} mode
    </button>
  );
}

Drop the pre-built AppearanceSwitcher component anywhere in your layout for a ready-made light/dark/system toggle:

tsx
import { AppearanceSwitcher } from "@tailor-platform/app-shell";

<AppearanceSwitcher />;

Theme Palettes

AppShell ships three palettes, each with light and dark variants:

PaletteCSS import
defaultIncluded automatically via @tailor-platform/app-shell/styles
cream@tailor-platform/app-shell/themes/cream
bloom@tailor-platform/app-shell/themes/bloom

Select a palette by importing its CSS file — no prop needed. Import it in your global CSS after @tailor-platform/app-shell/styles:

css
@import "@tailor-platform/app-shell/styles";
@import "@tailor-platform/app-shell/themes/cream"; /* overrides default palette */
@import "tailwindcss";

Only import one palette at a time.

Z-Index Layering

AppShell defines CSS custom properties for z-index values so you can adjust the stacking order to integrate with other libraries or overlays in your application.

These properties are defined in :root and can be overridden in your own CSS:

PropertyDefaultUsed for
--z-sidebar10The sidebar panel
--z-sidebar-rail20The sidebar collapse rail / toggle button
--z-popup50Portal-based popups (Menu, Select, Combobox, Autocomplete, Tooltip)
--z-overlay50Modal overlays (Dialog, Sheet)

Example: Raising popup z-index

css
/* your-app/globals.css */
@import "tailwindcss";
@import "@tailor-platform/app-shell/styles";

:root {
  --z-popup: 100;
}

Adding a palette

Theme tokens live in packages/core/src/assets/themes/. Copy _template.css to start a new palette — it lists exactly which sections to fill in for light and dark mode.

SectionRequired?What to set
1. BrandYesprimary, secondary, accent (+ foregrounds) — both modes
2. Shell gradientBranded palettes only--shell-gradient-base, --shell-gradient-tint
3. SystemTune or copy defaultSurfaces: background, card, popover, muted, borders
4. PaletteOptionalRadius, chart colors, shadows
5. SemanticDo not duplicateStatus and alert tokens inherit from default.css
6. StructuralBranded palettesCopy the structural override block from bloom.css or cream.css when needed

A palette is selected by CSS import, not by an AppShell prop. Import exactly one theme file after @tailor-platform/app-shell/styles; if you import none, the default palette from styles is used.

Preview token values at /custom-page/color in the Next.js example app.

Or skip the local setup: theme.tailor.tech takes a primary color, previews it on real AppShell components, and exports a themes/{name}.css structured according to the tier table above.