π¨βTheming
How do I change the colours, fonts, and overall look of a deck?
Tailwind first
Every Narro component takes className, and it is merged with the componentβs
own classes rather than replacing them. Where the two conflict, yours wins:
<Heading className="text-[13rem]"> is 13rem, not the levelβs default size, and
you never need an ! prefix to say so. For most decks this is the whole theming
story:
<Slide className="bg-gradient-to-br from-slate-900 to-blue-950">
<Heading level={1} className="text-accent">Title</Heading>
</Slide>
In markdown, the same thing via the attribute syntax:
# Title {.text-accent}
β¦or class: in slide frontmatter to style the whole slide, or on the deck
frontmatter to set a default for every slide.
Colours that follow the theme
text-accent above is not a colour someone chose. It is the themeβs accent, and
it changes when theme: changes β no deck.css, no component, no React.
Every built-in theme defines the same six colour roles and three font roles, and Narro emits them as Tailwind theme tokens, so each one is a whole utility namespace:
| Roles | Utilities |
|---|---|
accent, background, foreground, muted, primary, secondary | text-*, bg-*, border-*, ring-*, from-*, and the rest of the colour namespace |
heading, body, mono | font-body, font-heading, font-mono |
The whole list is in catalog.json under themeUtilities.
Use a role wherever the colour is a role. A callout border, a highlighted card, an emphasised heading, the good branch of a diagram β those are βthe accent colourβ, not βcyan 400β, and writing them as roles is what lets one deck ship in eleven themes:
:::{.border-l-4 .border-accent .bg-foreground/5 .p-6}
This card restyles itself with the deck.
:::
Reach for a palette colour when the colour is the point. A chart series where
red means βworseβ, a brand swatch, a screenshotβs matching background β those
should not move when the theme does. {.bg-cyan-400} names a fixed hue and keeps
it, which is correct here and wrong for the card above.
The distinction matters most in single-file markdown mode, where a deck.css is
not available: a deck built out of palette colours is locked to one theme by
construction, and a deck built out of roles is not.
Themes
@getnarro/marketplace ships themes as design tokens plus optional layout
overrides:
narro themes # browse and apply
---
theme: corporate-dark
---
Built-in themes: default, corporate-dark, minimalist-light, creative-gradient, ocean-blue, forest-green, sunset-warm, midnight-purple, tech-dark, startup-bold, academic-classic.
Colour schemes: ocean-blue, sunset-warm, forest-mist, royal-purple, rose-gold, arctic-blue, charcoal-slate, emerald-night.
A theme can also supply layouts. Layout names resolve most-specific-first β the
deckβs own layouts/ directory, then the deck template, then the theme, then
the built-ins β so overriding one layout never means forking the others.
Themes and deck templates
A theme is a palette someone else shipped. A deck template is the house style for your deck: one file beside it holding the tokens, the chrome every slide carries β footer, logo, slide numbers β and a set of layouts addressed by id.
| Theme | Deck template | |
|---|---|---|
| Where it comes from | @getnarro/marketplace, by name | a file beside the deck |
| What it sets | colours and fonts | colours, fonts, chrome, layouts, defaults |
| Named layouts | a theme may ship some | that is the point of it |
Checked by narro check | the name exists | the whole shape, plus every id and slot |
They compose: theme: for the palette, template: for the layouts, and the
template wins where they overlap. Reach for a theme to change how a deck looks
in one line; reach for a template when the same look has to hold across forty
slides.
Fonts
import { applyFontPreset } from "@getnarro/core";
applyFontPreset("inter");
Presets: system, inter, roboto, openSans, lato, montserrat, poppins, raleway, sourceSerif, playfairDisplay, merriweather, jetBrainsMono.
Or set them directly on the presentation:
<Presentation
theme={{
fontHeading: '"Inter", sans-serif',
fontBody: '"Inter", sans-serif',
fontMono: '"JetBrains Mono", monospace',
}}
>
Presets load from Google Fonts. If the roomβs network is unreliable, system
never fails β and a deck rendered in a fallback font is worse than one that
never asked for a webfont.
Design tokens
Themes expose Tailwind v4 @theme tokens, so custom colours are available as
utilities:
@theme {
--color-brand-500: #6366f1;
}
# Title {.text-brand-500}
What tone actually looks like
Badge, Card and Callout take a tone, and it is a colour role rather than
a colour β which is worth spelling out, because a role you cannot picture is a
prop you pass and then override:
tone | Colour | Follows the theme? |
|---|---|---|
default | The deckβs foreground at 5% background, 15% border | Yes β --slide-fg |
primary | --slide-primary at 12% / 45% (blue by default) | Yes |
accent | --slide-accent at 12% / 45% (violet by default) | Yes |
success | Green #16a34a at 14% / 50% | No β fixed |
warning | Amber #ca8a04 at 14% / 50% | No β fixed |
danger | Red #dc2626 at 14% / 50% | No β fixed |
The first three are the ones that carry a custom deck: they resolve through the
theme, so they change when it does. The last three are deliberately fixed β
green means passing everywhere β which also means that on a deck with its own
palette they are the three you are most likely to override with className.
That is expected, and className wins.
Practical advice
Two font sizes and two colours will carry an entire deck. Contrast that reads on your laptop often disappears on a washed-out projector, so err darker on light backgrounds and lighter on dark ones. And whatever you pick, apply it on the deck frontmatter rather than per slide β it is the difference between changing one line later and changing forty.