# Theming

- Page: https://koobiq.io/en/main/theming/overview

A theme in Koobiq is a set of CSS variables. Switching a theme swaps the values; nothing else has to change. This guide shows how to plug a theme in, how to switch it, and how to use its values in your own styles.

## How theming works

There are three layers.

**Global variables** describe the design system: colors, sizes, fonts. They come from the `@koobiq/design-tokens` package and are declared under the theme selector — `.kbq-light` or `.kbq-dark`. These are the values you reach for in your own styles.

**Component variables** are used inside Koobiq components. Each one is named after its component (`--kbq-button-*`, `--kbq-alert-*`) and points to a global variable. The component declares them itself, so nothing extra has to be included. The exception is code-block, scrollbar and skeleton: their tokens live in `@koobiq/design-tokens`, but with the default setup nothing has to be done for them either — their values are already part of the prebuilt styles.

**Your styles** use the global variables directly. No imports, no mixins, no registration in a single theme entry point.

Adding a theme to the page means putting a class on `<body>`. Everything below it — components and your own markup alike — picks up the new values automatically, because all of it reads the same variables.

## Setup

- [Install the Koobiq package](https://koobiq.io/en/main/installation.md).
- Include `css-tokens.css`, `css-tokens-light.css` and `css-tokens-dark.css` — these hold the global values.
- Include the prebuilt styles in your main stylesheet. Components and overlays (popups, dropdowns) need this to render correctly. It also carries the token values of code-block, scrollbar and skeleton, so no separate files are needed for them:

```scss
@use '@koobiq/components/prebuilt-themes/theme.css';
```

- Add the theme class to `<body>`:

```html
<body class="kbq-app-background kbq-light">
    <app></app>
</body>
```

`kbq-app-background` paints the page itself — background and text color.

- Import a component and use it. 🚀

## Switching themes

Use `KbqThemeService`. It puts the right class on `<body>`, remembers the choice, and in `'auto'` mode follows the system color scheme.

There are three modes: `'light'`, `'dark'` and `'auto'`. **`'auto'` is the default.** The system color scheme is supported out of the box: no `matchMedia` subscription of your own.

The service exposes its current state as signals, so you can read it straight from a template:

```ts
protected readonly themeService = inject(KbqThemeService);
```

```html
<button kbq-button (click)="themeService.toggle()">
    {{ themeService.colorScheme() === 'dark' ? 'Light theme' : 'Dark theme' }}
</button>
```

If you have more than two themes and need a list rather than a light/dark switch, you can pin one by name. See [Core](https://koobiq.io/en/components/core.md) for the details and a live example.

### Theme selectors

| Theme | Selector   |
| ----- | ---------- |
| Light | .kbq-light |
| Dark  | .kbq-dark  |

### Settings

Pass the settings when the app starts:

```ts
import { kbqThemeProvider } from '@koobiq/components/core';

bootstrapApplication(AppComponent, {
    providers: [kbqThemeProvider({ mode: 'auto', storageKey: 'my-app-theme' })]
});
```

The choice is saved between visits — in `localStorage` by default, where switching the theme in one tab is picked up by the app's other open tabs. Apps rendered on the server can store it in a cookie instead, so the server already knows which theme to render: provide `KbqThemeCookieStore` through the `KBQ_THEME_STORE` token. It reads the cookie straight off the incoming request, so nothing else has to be wired up on the server.

## Using theme values in your own styles

Write the variable where you need the value:

```css
.my-component-text {
    color: var(--kbq-foreground-contrast-secondary);
}
```

Nothing to import, no mixin to write, nothing to register in a single theme entry point. The value resolves in the browser, so it changes on its own when the theme changes.

[**Example: Theme values in your own styles** (`theme-css-variables`)](https://koobiq.io/examples/theme-css-variables.md)

The full list of global variables is on the [Design tokens](https://koobiq.io/en/main/design-tokens.md) page.

## Overriding a component's variables

When a component's default look doesn't fit, change the values of its variables rather than its styles. Start by knowing where those variables are declared, because that determines how you reach them. Every component sets them on its own selector, in a file next to itself:

```css
/* button-tokens.scss */
.kbq-button,
.kbq-button-icon {
    --kbq-button-filled-contrast-fade-off-background: var(--kbq-background-contrast);
}
```

The button sets the variable on itself, so a blanket declaration in `:root` simply won't be seen. For an override to work, you have to hit that same element.

That leaves two approaches.

**Change a single instance.** Give it a class of your own and set the variable there. The class lands on the same element as the default value and, coming later, wins:

```html
<button kbq-button class="my-danger-button">Delete</button>

<style>
    .my-danger-button {
        --kbq-button-filled-contrast-fade-off-background: var(--kbq-background-error);
    }
</style>
```

**Change every component of that type in the app.** This needs a selector that outranks the component's own. The simplest one to add is the theme selector — which also lets you give light and dark different values, when one color won't do for both:

```css
.kbq-light .kbq-button {
    --kbq-button-filled-contrast-fade-off-background: var(--kbq-background-error);
}

.kbq-dark .kbq-button {
    --kbq-button-filled-contrast-fade-off-background: var(--kbq-background-error-fade);
}
```

Rules like these are worth keeping in one file, loaded after the design system's styles — then all of the app's overrides live in one place instead of scattering across components.

## Building your own component

Your component reads the same global variables the library reads. Give it a stylesheet and turn off style encapsulation — that is the whole setup:

```ts
@Component({
    selector: 'my-card',
    templateUrl: './my-card.html',
    styleUrl: './my-card.scss',
    encapsulation: ViewEncapsulation.None,
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class MyCard {}
```

```scss
.my-card {
    padding: var(--kbq-size-l);
    border: var(--kbq-size-border-width) solid var(--kbq-line-contrast-less);
    border-radius: var(--kbq-size-border-radius);

    background: var(--kbq-background-card);
    color: var(--kbq-foreground-contrast);
}
```

There is **no** need to write a separate `_my-card-theme.scss` mixin and then register it in a single theme entry point.

### Corner shape

Where the browser supports `corner-shape`, components round their corners with a squircle (`corner-shape: squircle`); other browsers get a plain radius. A squircle looks smaller than an arc of the same radius, so its radius is scaled up. To give your component the same corners as the library's, include the mixin:

```scss
@use '@koobiq/components/core/styles/common/squircle' as *;

.my-card {
    @include kbq-squircle(var(--kbq-size-border-radius));
}
```

Without SCSS, write the same rule by hand:

```css
.my-card {
    --my-card-radius: var(--kbq-size-border-radius);

    border-radius: var(--my-card-radius);
}

@supports (corner-shape: squircle) {
    .my-card {
        corner-shape: squircle;
        border-radius: clamp(
            var(--my-card-radius) * 1.85,
            var(--my-card-radius) * 2.3 - 3.6px,
            var(--my-card-radius) * 2
        );
    }
}
```

To change a library component's radius, set its variable (for example `--kbq-button-size-border-radius`) rather than `border-radius`. The scaling applies to the variable: a plain `border-radius` leaves the corner a squircle that looks too small. A component made round with `50%` also needs `corner-shape: round`.

## Rebranding with a single file

You can restyle the whole app by overriding CSS variables in one place:

```css
.kbq-light {
    --kbq-background-contrast: #1a3a6b;
    --kbq-foreground-contrast: #0d1b2a;
}

.kbq-dark {
    --kbq-background-contrast: #7ba7e8;
    --kbq-foreground-contrast: #e8eef7;
}
```

Load that file after the design system's own, and every component follows.

One honest limitation: this works at the global layer. Component variables are declared on the component's selector, so a single global file can't reach them — you would need a rule per component, as shown above.

## Where to find the variables

Global variables, with their values and previews: [Design tokens](https://koobiq.io/en/main/design-tokens.md).

The variables of a component are declared next to its code, in its tokens file, such as `button-tokens.scss` for the button: open it from the **Source code** link on the page of the component. In a browser, the developer tools show them on the element of the component, as custom properties such as `--kbq-button-*`.

## Where the values come from

**Design system tokens** are the values that define how our components look. They live in the [@koobiq/design-tokens](https://github.com/koobiq/design-tokens) package.

**Component variables** are the values used inside component styles. They are derived from the design tokens and live in the `@koobiq/components` repository, next to the components themselves.

Note

Version 4.0.0 of `@koobiq/design-tokens` removed the component tokens, except for code-block, scrollbar and skeleton. Their tokens ship as separate files — `component-tokens.css` and its light and dark parts — and their values are already part of `@koobiq/components`' own `prebuilt-themes/theme.css`, so you don't need to load them yourself. Everything else is carried by the components themselves. If copies of the removed tokens are still in your own `css-tokens.css`, `css-tokens-light.css`, `css-tokens-dark.css` or `css-tokens-font.css`, delete them, and run `npx koobiq-tokens-codemod src` to find what else the upgrade touches.
