Skip to content
Blog

Theming and Layout in Astryx: Theme System, Frame-First Approach, and Templates

Master Astryx theming with 7 built-in themes, custom theme creation via defineTheme(), frame-first layout patterns, and page/block templates.

Published on July 31, 2026

AI Assistant

Astryx’s theme system and layout approach work together to produce consistent, theme-agnostic UIs. The core idea: your app code never references specific colors or measurements. Switch themes without touching a single line of application logic.

The Theme System

Built-in Themes

Astryx ships with 7 themes. Each is a separate npm package:

ThemePackageCharacter
Matcha@astryxdesign/theme-matchaEarthy green, Figtree typography
Neutral@astryxdesign/theme-neutralMuted, minimal, system fonts
Butter@astryxdesign/theme-butterGolden surfaces, blue accents
Chocolate@astryxdesign/theme-chocolateWarm brown/beige, Fraunces typeface
Gothic@astryxdesign/theme-gothicDark-only, deep blue-gray
Stone@astryxdesign/theme-stoneWarm stone/slate, Montserrat + Figtree
Y2K@astryxdesign/theme-y2kRetro pop, periwinkle, holographic

The Theme Component

Wrap your app (or a section) with <Theme> to activate a theme:

import { Theme } from '@astryxdesign/core/theme';
import { neutralTheme } from '@astryxdesign/theme-neutral/built';

function App() {
  return (
    <Theme theme={neutralTheme} mode="system">
      <YourApp />
    </Theme>
  );
}

The mode prop accepts 'system' (follows OS preference), 'light', or 'dark'.

Nesting Themes

Different sections can use different themes:

<Theme theme={matchaTheme}>
  <App>
    <Theme theme={neutralTheme}>
      <NeutralSection />
    </Theme>
  </Theme>
</Theme>

MediaTheme — Automatic Light/Dark Switching

Switch themes automatically based on prefers-color-scheme:

import { MediaTheme } from '@astryxdesign/core/MediaTheme';

<MediaTheme light="matcha" dark="gothic" />

No page refresh needed — it switches instantly.

Custom Themes with defineTheme()

Create fully custom themes with defineTheme(). You can configure colors, typography, radii, motion, and component overrides.

Simple Custom Theme

import { defineTheme } from '@astryxdesign/core/theme';

const myTheme = defineTheme({
  name: 'custom',
  tokens: {
    '--color-accent': '#FF6B35',
    '--color-background-surface': '#FEF9EF',
    '--color-text-primary': '#1A1A2E',
  },
});

Advanced Theme Configuration

const advancedTheme = defineTheme({
  name: 'my-theme',
  color: {
    accent: '#7B61FF',
    neutralStyle: 'cool',
  },
  typography: {
    scale: { base: 14, ratio: 1.2 },
    body: { family: 'Inter', fallbacks: '-apple-system, sans-serif' },
    heading: { family: 'Inter', weight: 'bold' },
    code: { family: 'JetBrains Mono' },
  },
  radius: { base: 4, multiplier: 1 },
  motion: { fast: 175, medium: 410, ratio: 0.75 },
  components: {
    button: {
      base: { borderRadius: '9999px', textTransform: 'uppercase' },
    },
    card: {
      base: { borderRadius: '20px', padding: '24px' },
    },
  },
});

Extending a Built-in Theme

import { defineTheme } from '@astryxdesign/core/theme';
import { neutralTheme } from '@astryxdesign/theme-neutral';

const brandTheme = defineTheme({
  name: 'brand',
  extends: neutralTheme,
  tokens: {
    '--color-accent': ['#7B61FF', '#9B85FF'],
  },
});

Building Themes for Production

npx astryx theme build ./src/themes/ocean.ts

Generates: ocean.css, ocean.js, ocean.d.ts, ocean.variants.d.ts.

useTheme Hook

Access current theme tokens and mode in JavaScript:

import { useTheme } from '@astryxdesign/core/theme';

function ChartConfig() {
  const { mode, tokens } = useTheme();
  const options = useMemo(() => ({
    textColor: tokens['--color-text-primary'],
    gridColor: tokens['--color-border'],
  }), [mode, tokens]);
  return <Chart options={options} />;
}

Frame-First Layout Approach

The fundamental rule: decide the frame before writing any content.

The 4-Step Process

  1. Pick the shellAppShell (top/side nav), Layout + LayoutPanel (multi-pane), or plain content column
  2. Budget regions in px — side nav 240-280, icon rail 64-72, inspector 340-420, filter/facet rail 220-260
  3. Decide container policy — dense data = rows, widgets = cards
  4. Write the responsive contract — which regions collapse/overlay/drop at which breakpoints

Three-Region Tool Frame

<AppShell
  sideNav={<SideNav>{/* items */}</SideNav>}
  contentPadding={0}
>
  <Layout>
    <LayoutContent>{/* dense list or table, edge-to-edge */}</LayoutContent>
    <LayoutPanel
      width={380}
      resizable={{ minSizePx: 320, maxSizePx: 480, autoSaveId: 'inspector' }}
      hasDivider isScrollable label="Details"
    >
      {selected ? <DetailFields item={selected} /> : <EmptyState title="Nothing selected" />}
    </LayoutPanel>
  </Layout>
</AppShell>

App Archetypes

ArchetypeFrameContainer Policy
Tracker / work toolAppShell + SideNav; inspector panel on selectRows only. Zero cards.
Console / observabilityAppShell + SideNav or TopNav + TabListCard grid for widgets; Table for everything else
Messaging / feedRail + sidebar + stream + panelRows and bubbles. No cards in the stream.
Media library / galleryAppShell + TopNav; grid contentCard grid with ClickableCard
Settings / formsAppShell + SideNav or settings templateSections with FormLayout; Card only for dangerous sections

Cards vs Rows (Anti-Pattern: “Card Soup”)

UseFor
Table (with plugins)Columnar records: hosts, deployments, users
List / Item (edge-to-edge)Single-line records: issues, files, conversations
CardSelf-contained widgets: KPI tiles, chart panels, gallery entries

Templates

Astryx provides page and block templates to jumpstart development.

Page Templates

  • AppShellTopNavWithSideNav — Full app shell with top nav + side nav + resizable content area
  • SettingsPage — Settings with sections, side nav for category selection
  • DashboardPage — Grid of cards for KPI/widget display

CLI Commands

npx astryx template --list                           # list all templates
npx astryx template --list --type page               # filter page templates
npx astryx template DashboardPage --skeleton          # study structure only
npx astryx template DashboardPage ./src/app           # scaffold into project