---
title: "Theme"
description: "Add keyframes and Tailwind-style animation strings through extendedTheme."
canonical_url: "https://vinicunca.dev/unocss-preset/getting-started/theme"
---
# Theme

> Add keyframes and Tailwind-style animation strings through extendedTheme.

`VinicuncaTheme` is UnoCSS [preset-wind4 `Theme`](https://unocss.dev/presets/wind4). `extendedTheme` takes a `VinicuncaExtends` object, which has only two fields: `keyframes` and a string-form `animation` map.

```ts
import type { CSSObject } from 'unocss';

interface VinicuncaExtends {
  keyframes?: Record<string, Record<string, CSSObject>>;
  animation?: Record<string, string>;
}
```

The preset merges these two fields into the UnoCSS theme. Keyframes become `theme.animation.keyframes`. Animation strings are parsed into `durations`, `timingFns`, and `counts`.

The preset reads no other fields from `extendedTheme`. Put colors, spacing, and other tokens on the UnoCSS `theme` option in `defineConfig`.

> [!WARNING]
> 
> Use `extendedTheme`, not UnoCSS `theme.animation` alone, when you want this string format. Do not reuse built-in names such as `spin` unless you intend to replace them.

## Keyframes and animation

Each keyframe name maps to a record of stop → CSS object (the same shape as a CSS `@keyframes` body, not `CSSKeyframesRule`).

Each animation value is a space-separated list:

`[name] [duration] [timing-function] [iteration-count]`

```ts [uno.config.ts]
import { presetVinicunca } from '@vinicunca/unocss-preset';
import { defineConfig } from 'unocss';

export default defineConfig({
  presets: [
    presetVinicunca({
      extendedTheme: {
        keyframes: {
          wiggle: {
            '0%, 100%': { transform: 'rotate(-3deg)' },
            '50%': { transform: 'rotate(3deg)' }
          }
        },
        animation: {
          wiggle: 'wiggle 1s linear infinite'
        }
      }
    })
  ]
});
```

That yields `animate-wiggle` with duration `1s`, timing `linear`, and iteration `infinite`.

If the map **key** differs from the keyframe **name**, `animate-{key}` becomes an alias. It reuses the keyframes of `{name}`, including built-in ones such as `spin`:

```ts
animation: {
  wiggle: 'wiggle 1s linear infinite',
  shake: 'wiggle 500ms ease-in-out 2'
}
```

`animate-shake` then runs the `wiggle` keyframes with its own duration, timing, and count. `animate-wiggle` keeps `1s linear infinite`. The keyframes are emitted under the alias name, so the CSS is `animation: shake 500ms ease-in-out 2` with `@keyframes shake`.

## Placeholders

You can skip or blank a slot instead of omitting later values:

- `*` — do not inject that property into the UnoCSS theme
- `+` — inject the property, but with an empty string

```ts
extendedTheme: {
  animation: {
    foo: 'foo 1s * 3',
    bar: 'bar 1s +'
  }
}
```

`foo` keeps duration `1s` and count `3`, and skips the timing function. `bar` keeps duration `1s` and injects an empty timing function.

Duration also accepts CSS variables (`var(--duration)`). This docs hub uses the same API for accordion, collapsible, and toast keyframes in its `uno.config.ts`.


## Sitemap

See the full [sitemap](https://vinicunca.dev/sitemap.md) for all pages.
