Skip to content

Components

View Markdownllms.txt

A component is a named piece of slide that you define once and use as many times as you like. It takes parameters, like a template: the text changes, the look stays the same.

Components have no logic. There are no loops, conditions or calculations: Folio simply replaces each parameter with the value you give it.

Write the definition at the start of the document, together with @title, @theme and the other definitions, before the first slide:

@component metric {value label color=accent}
::: box {.card align=center}
$value {size=5xl weight=bold color=$color}
$label {.muted}
:::
@end
  • @component is followed by the name and, in braces, the list of parameters.
  • Everything between that line and @end is the component body, written in the same language as your slides.
  • The name uses lowercase letters, numbers and hyphens, such as metric or team-card.
FormMeaning
valueRequired parameter. Using the component without it is an error.
color=accentParameter with a default value. If you leave it out, it is accent.
title="Untitled"Default value with spaces, in quotes.

Inside the body, $name is replaced by the parameter value. This works anywhere:

  • in text: ## $title or Owner: $name;
  • in attribute values: {color=$color} or {bg=$background};
  • on a line of its own: $label becomes a paragraph with the value.

The value can contain text formatting, such as **bold**, and it is applied on the slide.

There are two ways to use a component, the same as for language blocks:

  • Single line, with ::, when it has no content: :: metric {value=38% label="revenue growth"}.
  • Container, with ::: and a closing :::, when it takes content (see the next section).

Parameters go in braces, always by name. Values with spaces go in quotes.

@component metric {value label color=accent}
::: box {.card align=center}
$value {size=5xl weight=bold color=$color}
$label {.muted}
:::
@end
# Quarterly results
::: grid {cols=3 gap=lg}
:: metric {value=38% label="revenue growth"}
:: metric {value=94 label="new customers" color=green}
:: metric {value=4.8 label="satisfaction score" color=violet}
:::

When you use the component as a container, everything between the opening and closing lines goes into $content. Put $content on a line of its own, at the point in the body where the content should appear:

@component highlight {title}
::: box {.card gap=sm}
## $title
$content
:::
@end
::: highlight {title="Next steps"}
- Review the budget with the board
- Hire two people for support
- Launch the new plan in March
:::

The content can be anything: text, lists, images, other blocks and other components.

Sometimes a component needs more than one content area, such as the two columns of a comparison. That is what named slots are for:

  1. In the component body, write $slot-name on a line of its own, using a name that is not a parameter.
  2. When using the component, fill the slot with a ::: slot slot-name … ::: block.
  3. The rest of the content still goes into $content.
@component comparison {before after}
::: columns {gap=xl}
::: box {.card gap=sm}
## $before
$content
:::
::: box {.card gap=sm bg=accent color=white}
## $after
$result
:::
:::
@end
::: comparison {before="Scattered spreadsheets" after="A single dashboard"}
Each team exports, pastes and formats the numbers by hand.
::: slot result
The data arrives on its own and the report refreshes every hour.
:::
:::

Slots you do not fill stay empty, with no error. Filling a slot the component does not have is an error, and the editor suggests the closest name.

A component body can use other components, and so can the content you pass to a component:

@component badge {text}
::: box {bg=accent color=white pad=sm radius=lg}
$text {size=sm weight=bold uppercase}
:::
@end
@component plan {name price}
::: box {.card gap=sm}
:: badge {text=$name}
## $price
$content
:::
@end
::: grid {cols=2 gap=lg}
::: plan {name=Essential price="$9"}
Up to 5 users
:::
::: plan {name=Team price="$29"}
Unlimited users
:::
:::

A component cannot use itself, either directly or indirectly (for example, a uses b and b uses a). Folio detects the cycle and shows an error. Components can be nested up to 16 levels deep.

The step attribute also works on a component call. The whole component appears at the given step:

:: metric {value=38% label="growth" step=1}
:: metric {value=94 label="new customers" step=2}

Learn more in Step-by-step reveal.

Components only accept parameters. Styles such as .card and #id on the call are an error. To change how one particular use looks, wrap the component in a box:

::: box {.dark pad=lg}
:: metric {value=38% label="growth"}
:::

If the change should always apply, create a parameter instead, like color=accent in the metric example.

CodeWhen it happens
F401$content was used outside a @component.
F404The component uses itself, directly or indirectly.
F405Components nested more than 16 levels deep.
F406The call has a .style or #id. Wrap the component in a box.
F407The call passes a parameter the component does not have.
F408The call has loose text instead of parameters in braces.
F409A required parameter is missing.
F410The body uses $name, but name was not declared as a parameter.
F411Warning: the component received content but does not use $content.
F412The component name is the name of a language block.
F413The same component was defined twice in the document.
F414::: slot fills a slot the component does not have.
F415::: slot without the slot name.
F416::: slot outside a component call.
F417The same slot was filled twice.
F504@component without a matching @end.
F511Invalid component name (use lowercase letters, numbers and hyphens).

Errors inside a component body are reported on the line where the component is used, with the note “(in component name)”. The full list is in Error messages.