# Theming

> Set your app's colour theme, shape, scale and text preferences with data attributes.

Source: /docs/theming

After [importing the theme](/docs/installation), set data attributes on `html` or another ancestor. Components and token utilities inside it use the selected values.

Try each option in the [Playground](/playground) before applying it in your app. It shows the settings on real components and gives you the code for your configuration.

## Base defaults

Each axis has its own `base` value. The table shows what that value selects.

| Axis        | Attribute                    | Base maps to                     | Example                                                                                    |
| ----------- | ---------------------------- | -------------------------------- | ------------------------------------------------------------------------------------------ |
| Theme       | `data-theme="base"`          | Default light palette            | Body text is dark on a light background.                                                   |
| Font        | `data-fontfamily="base"`     | Aksara fonts                     | Display, body and code text use Aksara.                                                    |
| Shape       | `data-shape="base"`          | Standard radii and border widths | The 16px radius token is 16px. The 1px border token is 1px.                                |
| Scale       | `data-scale="base"`          | `1x`                             | The 16px spacing token is 16px.                                                            |
| Font size   | `data-fontsize="base"`       | `16px` preset                    | Body text is 16px.                                                                         |
| Line height | `data-fontlineheight="base"` | `ThaiFont`                       | Body text has a 28px line height at the 16px preset.                                       |
| Breakpoint  | `data-breakpoint="base"`     | `mobile`                         | The reference width is 376px, horizontal padding is 16px and modal-width tokens are 352px. |

Setting `data-theme="base"` changes only the colour theme. It does not reset fonts, shape, scale, font size, line height or breakpoint. Set each attribute to `base` to select all the defaults explicitly.

The breakpoint default selects mobile token values, not a mobile browser width.

## What each axis changes

- Theme selects a colour palette. The options are light, dark and high-contrast.
- Font selects a font profile. The options are Aksara, Sarabun and Arena.
- Shape changes corner-radius and border-width tokens.
- Scale changes spacing tokens.
- Font size changes text-size tokens.
- Line height selects the English or Thai text metrics.
- Breakpoint selects responsive token values, such as page padding and dialog widths. It does not resize your browser or change viewport-based CSS media queries.

## Dark mode

Set `data-theme="dark"` on `html` to apply dark colours across your app.

```html
<html data-theme="dark"></html>
```

To switch back to the default light theme, set `data-theme="base"`. A theme control in your app can update the attribute with [`ThemeProvider`](/docs/theme-provider) and `useTheme`.

```tsx
'use client'

import { Button, useTheme } from '@aksornproject/aksara-ui'

export function ThemeToggle() {
  const { theme } = useTheme()

  return (
    <Button onClick={() => theme.toggle('dark', 'base')}>
      Toggle colour theme
    </Button>
  )
}
```

Render it under `<ThemeProvider target="html" persist>`. The provider saves the choice and applies it before the page paints on the next visit. If you use another theme provider, configure it to update `data-theme` with the values below.

The library's Tailwind `dark:` variant matches `data-theme="dark"` on the element or an ancestor, rather than a `.dark` class.

## Available colours

| `data-theme` | Use                 |
| ------------ | ------------------- |
| `base`       | Default light       |
| `dark`       | Dark                |
| `light-hc`   | High-contrast light |
| `dark-hc`    | High-contrast dark  |

Use semantic colour utilities such as `bg-color-background-body` and `text-color-text-primary` so your own layouts follow the theme too. Preview their values on the [Colors](/docs/foundations/colors) page.

## Fonts

`theme.css` declares Aksara in weights 400, 500, 600 and 700, the weights the typography tokens use. The default font profile needs nothing else. The browser downloads only the weights a page renders, and shows the fallback font until each one arrives.

The other font profiles name fonts that `theme.css` doesn't load. Import the entry for each profile your app uses, after the theme.

| `data-fontfamily`     | Fonts                             | Import                                                   |
| --------------------- | --------------------------------- | -------------------------------------------------------- |
| `base`                | Aksara                            | Nothing                                                  |
| `aksornfirst-sarabun` | Sarabun                           | `@aksornproject/aksara-ui/fonts/aksornfirst-sarabun.css` |
| `arena`, `arena-2`    | Fredoka, Nunito Sans, Roboto Mono | `@aksornproject/aksara-ui/fonts/arena.css`               |

```css title="app.css"
@import 'tailwindcss';
@import '@aksornproject/aksara-ui/theme.css';
@import '@aksornproject/aksara-ui/fonts/arena.css';
```

Each entry loads weights 400 to 700. The font files are split by script, so a page with only Latin text skips the Thai files. An entry you don't import adds nothing to your build.

### Fallbacks

Every font family ends in `Aksara, system-ui, sans-serif`. The browser uses Aksara for any character the theme's font lacks. Fredoka, Nunito Sans and Roboto Mono have no Thai characters, so Thai text in `arena` and `arena-2` renders in Aksara. If you skip an entry, the browser uses a copy of that font installed on the device, and Aksara when there is none.

### Serve the fonts yourself

To serve Aksara from your own server or CDN, declare `@font-face` rules for `Aksara` after the theme import. When two rules declare the same family, weight and style, the browser uses the later one and doesn't download the bundled file.

```css title="app.css"
@import 'tailwindcss';
@import '@aksornproject/aksara-ui/theme.css';

@font-face {
  font-family: Aksara;
  src: url('https://cdn.example.com/Aksara-Regular.woff2') format('woff2');
  font-weight: 400;
  font-display: swap;
}
```

Repeat the rule for weights 500, 600 and 700. To serve a profile's fonts yourself, skip its entry and declare `@font-face` rules for the font names in the table.

## Shape and scale

You can apply these attributes to the whole app or limit them to a section.

| Attribute             | Values                                    | Controls                       |
| --------------------- | ----------------------------------------- | ------------------------------ |
| `data-fontfamily`     | `aksornfirst-sarabun`, `arena`, `arena-2` | Font profile fonts             |
| `data-shape`          | `base`, `fun`, `timeless`                 | Corner radii and border widths |
| `data-scale`          | `1x`, `1.25x`, `1.5x`                     | Spacing token values           |
| `data-fontsize`       | `16px`, `20px`, `24px`                    | Text size                      |
| `data-fontlineheight` | `EnglishFont`, `ThaiFont`                 | Language-specific line heights |
| `data-breakpoint`     | `desktop`, `laptop`, `ipad`, `mobile`     | Responsive token values        |

```tsx
<section data-theme="dark" data-fontfamily="arena">
  <Typography className="text-color-text-primary">
    ตั้งค่าการแจ้งเตือน
  </Typography>
</section>
```

The section renders dark colours with Fredoka headings and Nunito Sans body text.

These settings affect token-based styles. Fixed pixel values in your app do not scale with them.