Use Krysalicss with Astro

Astro speaks SCSS natively through its bundled Vite pipeline. Install the framework, import an SCSS entry from a layout, and the rest is authoring HTML. No integration plugin needed.

Install

Astro uses Vite under the hood and treats .scss files the same way Vite does: install the sass package and the framework.

Terminal
pnpm add -D sass @adnap/krysalicss

Wire the SCSS entry

Create a single SCSS entry under src/styles/. The framework's sass export condition resolves @adnap/krysalicss to src/krysalicss.scss — no alias config needed.

src/styles/app.scss
// src/styles/app.scss
@use '@adnap/krysalicss';

Import the entry once from a layout. Astro emits the result as a global stylesheet on every page that uses the layout, deduplicated automatically:

src/layouts/BaseLayout.astro
---
// src/layouts/BaseLayout.astro
import '../styles/app.scss';

interface Props {
  title: string;
}
const { title } = Astro.props;
---
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>{title}</title>
  </head>
  <body>
    <slot />
  </body>
</html>

You can also @use the framework inside an inline <style is:global lang="scss"> block, but the dedicated entry keeps overrides discoverable and avoids recompiling the same SCSS module graph for every page.

Override a variable

Place the configured @use ahead of the framework entry in your SCSS file. Sass picks up the override on first load:

src/styles/app.scss
// src/styles/app.scss
@use '@adnap/krysalicss/module/navbar' with (
  $gap: 1.5rem,
  $item-padding-x: 1rem,
);
@use '@adnap/krysalicss';

See Override component variables for the full override surface (per-component, root-level, selectors, palettes).

Strip unused modules

Pass $feature-list to the framework entry. Astro/Vite compiles only the slices you ask for:

src/styles/app.scss
// src/styles/app.scss
@use '@adnap/krysalicss' with (
  $feature-list: (
    base-reset,
    base-global,
    typography-base,
    typography-title,
    typography-link,
    typography-content,
    layout-container,
    layout-flex,
    element-button,
    module-card,
    module-navbar,
  ),
);

See Tree-shake to specific modules for the full flag inventory and the per-module import alternative.

Light + dark theme switching

The dark theme listens for prefers-color-scheme automatically. For a manual toggle, set the class on <html> from an inline script with is:inline so Astro emits it verbatim before hydration — that avoids the flash of light theme on first paint.

src/layouts/BaseLayout.astro
---
// src/layouts/BaseLayout.astro
import '../styles/app.scss';
---
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <script is:inline>
      try {
        const saved = localStorage.getItem('theme');
        if (saved === 'dark') document.documentElement.classList.add('theme-dark');
      } catch {}
    </script>
  </head>
  <body>
    <slot />
  </body>
</html>

The toggle button itself is a small island. The bundled Vue toggle component in the Krysalicss docs is one example; the same pattern works in any UI integration Astro supports:

src/components/ThemeToggle.vue
<script setup lang="ts">
function toggle() {
  const root = document.documentElement;
  root.classList.toggle('theme-dark');
  localStorage.setItem(
    'theme',
    root.classList.contains('theme-dark') ? 'dark' : 'light',
  );
}
</script>

<template>
  <button class="button" @click="toggle">Toggle theme</button>
</template>

See also