Formatting & Branding

Session 5

Session Overview

Session 5: Formatting & Branding

  • Theming & Brand.yml
    • Bootstrap 5 theme basics and brand.yml for cross-format consistency.
    • Colour palettes, typography, and logo management.
    • Using the brand.yml R and Python packages in code outputs.
  • Brand Extensions & quarto use brand
    • Packaging brand.yml as a Quarto extension for organisational reuse.
    • Importing brand configurations with quarto use brand.
    • Automation flags for CI workflows.
  • Pandoc Templating
    • Understanding Pandoc’s templating syntax fundamentals.
    • Variables, conditionals, and loops for dynamic content.
    • Modifying partials for custom output.
  • Typst Customisation (Optional)
    • Typst templates and partials for PDF branding.
    • Template structure and brand.yml integration.
    • Creating custom Typst formats with consistent visual identity.
  • Theming & Brand.yml
    • Bootstrap 5 theme basics and brand.yml for cross-format consistency.
    • Colour palettes, typography, and logo management.
    • Using the brand.yml R and Python packages in code outputs.
  • Brand Extensions & quarto use brand
    • Packaging brand.yml as a Quarto extension for organisational reuse.
    • Importing brand configurations with quarto use brand.
    • Automation flags for CI workflows.
  • Pandoc Templating
    • Understanding Pandoc’s templating syntax fundamentals.
    • Variables, conditionals, and loops for dynamic content.
    • Modifying partials for custom output.
  • Typst Customisation (Optional)
    • Typst templates and partials for PDF branding.
    • Template structure and brand.yml integration.
    • Creating custom Typst formats with consistent visual identity.

Session Objectives

This session explores Quarto’s branding capabilities, focusing on brand.yml as the central tool for unified branding across formats, the brand.yml R and Python packages for applying brand guidelines in code outputs, packaging brand configurations as extensions, and importing them with quarto use brand.

Learning Objectives

By the end of this session, participants will be able to:

  • Create unified branding across multiple output formats using brand.yml.
  • Use the brand.yml R and Python packages to apply brand guidelines in code outputs.
  • Develop brand extensions for organisational reuse.
  • Import and manage external brand configurations with quarto use brand.
  • Understand Pandoc’s templating syntax for dynamic content generation.
  • Understand the basics of Bootstrap theming in Quarto.

Theming (Bootstrap & Customisation)

Bootstrap in Quarto

Quarto HTML format uses Bootstrap 5, providing:

  • Several built-in themes from Bootswatch.
  • Responsive grid system.
  • Component library (e.g., buttons, cards, navigation).
  • Customisation system via CSS variables.

Theme Selection

Available themes: default, cerulean, cosmo, cyborg, darkly, flatly, journal, litera, lumen, lux, materia, minty, morph, pulse, quartz, sandstone, simplex, sketchy, slate, solar, spacelab, superhero, united, vapor, yeti, zephyr.

See HTML Theming for more.

  • Single theme.
yaml
format:
  html:
    theme: cosmo
  • Theme + customisation.
yaml
format:
  html:
    theme: [cosmo, custom.scss]

See HTML Theming and More About Quarto Themes for YAML options and SCSS customisation.

Tip

For most branding needs, brand.yml provides a simpler and more portable approach than custom SCSS, as we will see next.

brand.yml Foundation

Understanding Brand.yml

brand.yml is a single YAML file that codifies your organisation’s brand guidelines into a machine-readable format. It is used by Quarto, Shiny, and the brand.yml R and Python packages to create branded outputs across multiple formats and tools.

Key benefits:

  • Cross-format consistency - HTML, PDF, presentations share the same design.
  • Organisational standards - Teams work with unified branding.
  • Easy maintenance - Update once, apply everywhere.
  • Simple syntax - No complex CSS knowledge required.

Basic brand.yml Structure

Create a _brand.yml file in your project root:

_brand.yml
1meta:
  name: "Your Organisation"
  link: "https://yourorg.com"

2color:
  palette:
    primary: "#2E86AB"
    secondary: "#A23B72"
    light: "#F8F9FA"
    dark: "#343A40"
  primary: primary
  foreground: dark
  background: light

3logo:
  small: "assets/logo-small.png"
  medium: "assets/logo-medium.png"
  large: "assets/logo-large.png"

4typography:
  fonts:
    - family: "Inter"
      source: "google"
  base: "Inter"
  headings: "Inter"
1
Basic brand identity.
2
Colour palette system.
3
Logo management.
4
Typography system.

Colour Palette System

The palette defines named colours that can be referenced throughout your brand:

_brand.yml
color:
1  palette:
    ocean-blue: "#2E86AB"
    coral-pink: "#A23B72"
    sunshine: "#F4A261"
    forest: "#2A9D8F"
    charcoal: "#264653"
    pearl: "#F8F9FA"
  # Semantic assignments
  primary: ocean-blue
  secondary: coral-pink
  success: forest
  warning: sunshine
  foreground: charcoal
  background: pearl
1
Define a palette of named colours.

Cross-format usage:

  • HTML: Available as $brand-primary (SCSS), --brand-primary (CSS), etc.
  • Typst: Available as brand-color.primary, etc.
  • R/Python: Available via the brand.yml packages for plots, tables, and applications.

Typography Configuration

Define your organisation’s font system:

yaml
typography:
  fonts:
    # Google Fonts (automatically loaded)
    - family: "Inter"
      source: "google"
      weight: [300, 400, 500, 600, 700]

    # System fonts (fallback)
    - family: "system-ui"
      source: "system"

  # Font assignments
  base: "Inter"           # Body text
  headings: "Inter"       # All headings
  monospace: "SF Mono"    # Code blocks

See Typst Brand YAML for troubleshooting fonts in Typst.

Logo Management

Provide logos at different sizes for various contexts:

yaml
logo:
  # Favicon and small contexts
  small: "brand/favicon.png"

  # Navigation bars, headers
  medium: "brand/logo-nav.png"

  # Hero sections, print materials
  large: "brand/logo-full.png"
Logo usage across formats.
Format Location Logo Preference (high to low)
html/dashboard Top navigation bar small > medium > large
html Side navigation medium > small > large
typst Top left, control with format: typst: logo medium > small > large
revealjs Bottom right corner of slides medium > small > large
website/book project favicon shown in browser tab small

See Logo Configuration for more.

Logo usage across formats.
Format Location Logo Preference (high to low)
html/dashboard Top navigation bar small > medium > large
html Side navigation medium > small > large
typst Top left, control with format: typst: logo medium > small > large
revealjs Bottom right corner of slides medium > small > large
website/book project favicon shown in browser tab small

See Logo Configuration for more.

Brand Integration

Combine brand.yml with Bootstrap customisation:

_quarto.yml
format:
  html:
    theme:
      - cosmo
      - brand
      - styles.scss
1    css: custom-components.css
1
Prefer brand.yml or SCSS for component customisation.
Note

The brand colours become available as CSS variables and SCSS variables automatically.

brand.yml in R and Python

Brand Guidelines in Code Outputs

brand.yml is not limited to document theming. The R and Python packages let you apply brand colours, fonts, and logos directly in your code outputs.

Supported integrations:

  • Quarto (websites, presentations, dashboards, Typst documents).
  • Shiny for Python and Shiny for R (via bslib).
  • Custom R and Python visualisations (ggplot2, plotnine, great_tables, etc.).

See brand.yml for full documentation.

Using brand.yml in R

Install the package:

r
install.packages("brand.yml")

Read the brand and access its properties:

r
library(brand.yml)
brand <- read_brand_yml()

brand[["color"]][["palette"]][["primary"]]
brand[["color"]][["foreground"]]
brand[["typography"]][["base"]]

Apply to a ggplot2 visualisation:

r
library(ggplot2)
ggplot(data) +
  aes(x = x, y = y) +
  geom_point(colour = brand[["color"]][["palette"]][["primary"]]) +
  theme_minimal(base_family = brand[["typography"]][["base"]])

Using brand_yml in Python

Install the package:

bash
pip install brand_yml

Read the brand and access its properties:

python
from brand_yml import Brand

brand = Brand.from_yaml("_brand.yml")

brand.color.primary
brand.color.palette
brand.typography.base

Apply to a plotnine visualisation:

python
from plotnine import ggplot, aes, geom_point, theme, element_text

(
    ggplot(data, aes("x", "y"))
    + geom_point(colour=brand.color.primary)
    + theme(text=element_text(family=brand.typography.base))
)
Note

The brand.yml packages ensure that your data visualisations match your document branding without manual colour copying.

Hands-On Exercise: Setting Up a Brand

Exercise Overview

Objective: Create a _brand.yml file from scratch with a colour palette, typography, logos, and test it across multiple output formats.

Part 1: Create Brand Identity

  1. Create a new Quarto project:

    bash
    quarto create project default my-branded-project
    cd my-branded-project
  2. Create a _brand.yml file with:

    • meta: Organisation name and link.
    • color: A palette with at least primary, secondary, foreground, and background colours, plus semantic mappings.
    • typography: One or two Google Fonts for base and headings.
    • logo: References to logo files (add placeholder images to an assets/ directory).
  3. Add brand to your theme in _quarto.yml:

    yaml
    format:
      html:
        theme: [default, brand]

Part 2: Test Across Formats

  1. Add content to your index.qmd with headings, text, code blocks, and lists.

  2. Render and verify branding in HTML:

    bash
    quarto render
  3. Test in RevealJS:

    bash
    quarto render index.qmd --to revealjs
  4. Verify that colours, fonts, and logo appear consistently across both formats.

Part 3: Apply to Code Outputs

  1. Add a code block (R or Python) that uses brand colours from _brand.yml in a plot.

  2. Verify that the plot colours match the document branding.

Success Criteria

  • Create a working _brand.yml with colour palette, typography, and logo.
  • Consistent branding across HTML and RevealJS formats.
  • Logo displayed correctly in the output.

Brand Extensions Development

What Are Brand Extensions?

Brand extensions are Quarto extensions that provide a brand.yml file and its assets, packaged for easy distribution and reuse.

Key features:

  • Portable branding - Install everywhere.
  • Team consistency - Everyone gets the same brand.
  • Asset management - Logos and fonts included.
  • Version control - Track brand changes over time.
  • Importable - Use with quarto use brand for easy adoption.

Creating a Brand Extension

Step 1: Scaffold Extension

bash
quarto create extension brand my-brand
cd my-brand

This creates:

my-brand
|-- README.md
|-- _extensions
|   `-- my-brand
|       |-- _extension.yml
|       `-- brand.yml
|-- _quarto.yml
`-- example.qmd

2 directories, 5 files

Step 2: Configure Extension

Quarto
title: My-brand
author: First Last
version: 1.0.0
quarto-required: ">=1.9.0"
contributes:
  metadata:
    project:
      brand: brand.yml

Step 3: Design Brand System

_extensions/my-brand/brand.yml
meta:
  name: "My Organisation"
  link: "https://myorg.com"

color:
  palette:
    # Primary brand colours
    brand-blue: "#2E86AB"
    brand-coral: "#A23B72"
    brand-gold: "#F4A261"
    # Supporting colours
    neutral-light: "#F8F9FA"
    neutral-dark: "#343A40"
    success-green: "#28A745"
    warning-amber: "#FFC107"
  # Semantic mappings
  primary: brand-blue
  secondary: brand-coral
  success: success-green
  warning: warning-amber
  foreground: neutral-dark
  background: neutral-light

logo:
  small: assets/logo/favicon.png
  medium: assets/logo/logo-horizontal.png
  large: assets/logo/logo-vertical.png

typography:
  fonts:
    - family: "Source Sans Pro"
      source: "google"
      weight: [300, 400, 600, 700]

  base: "Source Sans Pro"
_extensions/my-brand/brand.yml
defaults:
  bootstrap:
    defaults:
      # Enhanced navigation
      navbar-padding-y: 1rem
      navbar-brand-font-size: 1.5rem

      # Improved buttons
      btn-padding-y: 0.5rem
      btn-padding-x: 1.5rem
      btn-font-weight: 600

      # Better spacing
      spacer: 1rem

    rules: |
      /* Professional enhancements */
      .navbar-brand {
        font-weight: 700;
      }

      .btn-primary {
        border-radius: 2rem;
        transition: all 0.3s ease;
      }

      .btn-primary:hover {
        transform: translateY(-1px);
      }

      /* Content styling */
      .title-block-header {
        padding: 3rem 2rem;
        margin-bottom: 2rem;
        border-radius: 0.5rem;
      }

Step 4: Add Assets

Organise brand assets:

txt
_extensions/my-brand/
├── _extension.yml
├── brand.yml
└── assets/
    ├── logo/
    │   ├── favicon.png
    │   ├── logo-horizontal.png
    │   └── logo-vertical.png
    └── fonts/
        └── custom-font.woff2

Step 5: Create Example

example.qmd
---
title: "Brand Extension Showcase"
subtitle: "Demonstrating consistent branding"
author: "Your Name"
format:
  html:
    theme:
      - quartz
      - brand
---

# Welcome to Our Brand System

This document demonstrates the power of brand extensions in Quarto.

[Primary Action]{.btn .btn-primary}
[Secondary Action]{.btn .btn-secondary}
Important

Brand extensions require a _quarto.yml project file to work.

quarto use brand

Importing Brand Configurations

The quarto use brand command copies brand files from an external source into your project’s _brand/ directory, making it easy to adopt shared organisational branding.

Supported sources:

  • Local directory: quarto use brand ./path/to/brand.
  • GitHub repository: quarto use brand myorg/shared-brand.
  • URL zip archive: quarto use brand https://example.com/brand.zip.

How quarto use brand Works

The command follows a structured workflow with user confirmations:

  1. Confirms trust for remote sources.
  2. Creates _brand/ directory if needed.
  3. Prompts before overwriting existing files.
  4. Copies all files from the source to _brand/.
  5. Asks whether to remove local files not present in the source.
Note

The result ensures your _brand/ directory matches the source exactly, making it easy to stay synchronised as shared brands evolve.

Flags for Automation

Preview changes without modifying files:

bash
quarto use brand myorg/shared-brand --dry-run

Skip all confirmation prompts for automated or CI workflows:

bash
quarto use brand myorg/shared-brand --force
Tip

Use --dry-run first to review what will change, then --force in CI pipelines. See Brand for complete documentation.

Hands-On Exercise: Building Your Brand Extension

Exercise Overview

Objective: Create a comprehensive brand extension that demonstrates unified branding across formats using brand.yml and light CSS customisation.

Example Code: Exercises Brand

bash
tar -xzf "05a-exercises.tar.gz" -C "05-formatting-branding"

Part 1: Brand Extension Setup

  1. Generate extension scaffold:

    bash
    quarto create extension brand my-company-brand
    cd my-company-brand
  2. Define your brand identity.

  3. Add styling.

Part 2: Testing

  1. Build test project:

    bash
    quarto create project
  2. Test across formats:

    bash
    # Test HTML output
    quarto render example.qmd --to html
    
    # Test presentation
    quarto render example.qmd --to revealjs
    
    # Test Typst output
    quarto render example.qmd --to typst
  3. Verify brand consistency.

Success Criteria

You’ve successfully completed the exercise if you can:

  • Create a working brand extension with consistent visual identity.
  • Implement styling using brand.yml and light (S)CSS.
  • Test the brand system across multiple formats.
  • Demonstrate cross-format consistency.
  • Build a reusable brand asset for teams.
  • Apply design principles effectively.

Pandoc Templating System

Understanding Pandoc Templates

Quarto uses Pandoc’s templating system to generate output.

Key concepts:

  • Variables - $variable$ inserts YAML metadata.
  • Conditionals - $if(variable)$...$endif$ for optional content.
  • Loops - $for(variable)$...$endfor$ for repeated content.
  • Partials - Reusable template components.

See Pandoc Template Syntax for complete documentation.

Basic Variable Syntax

Variables from YAML front matter are inserted using $variable$:

Quarto Document
---
title: "My Report"
author: "Jane Smith"
date: "2025-01-15"
---
Template Input
Title: $title$
Author: $author$
Date: $date$
Template Output
Title: My Report
Author: Jane Smith
Date: 2025-01-15
Tip

Use $variable$ in any template file (.typ, .tex, .html, etc.).

See Article Templates for templates and partials.

Conditional Content

Show content only when a variable exists:

Quarto Document
---
title: "Report"
subtitle: "Q4 Analysis"
# No author specified
---
Note

Use $if(variable)$...$else$...$endif$ for alternative content.

Template Input
Title: $title$

$if(subtitle)$
Subtitle: $subtitle$
$endif$

$if(author)$
Author: $author$
$endif$
Template Output
Title: Report
Subtitle: Q4 Analysis
Important

$if(variable)$ in Pandoc templates checks if a variable is:

  • Defined (exists in the metadata).
  • Non-empty (has a value).
  • Not explicitly false.

Loops for Multiple Items

Process lists from YAML metadata:

Quarto Document
---
authors:
  - name: Jane Smith
    email: jane@example.com
  - name: John Doe
    email: john@example.com
---
Template Input
Authors:
$for(authors)$
- $it.name$ ($it.email$)
$endfor$
Template Output
Authors:
- Jane Smith (jane@example.com)
- John Doe (john@example.com)
Note

Use $it$ to reference the current item in a loop. Use $sep$ followed by the separator string for separators.

Separator Usage

Add separators between items:

Quarto Document
---
tags:
  - Research
  - Data Science
  - Machine Learning
---
Template Input
Tags: $for(tags)$$it$$sep$, $endfor$
Template Output
Tags: Research, Data Science, Machine Learning
Template Input
Tags: $for(tags)$$it$$endfor$
Template Output
Tags: ResearchData ScienceMachine Learning

Hands-On Exercise: Pandoc Templating

Exercise Overview

Objective: Modify a partial template to display additional metadata using Pandoc templating syntax.

Example Code: Exercises Partials

bash
tar -xzf "05b-exercises.tar.gz" -C "05-custom-partials"

Part 1: Template Modification

  1. Retrieve the partials described in Article Templates

  2. Modify the title slide partial from Reveal.js to underline the corresponding author:

    • Use $if(by-author)$ to check for by-author metadata.
    • Loop through by-author to find the corresponding author and underline their name.
    • See Author Schema for details.

Part 2: Customise Further

  1. Add additional metadata to the title slide, such as affiliations or ORCID IDs.

  2. Test the changes by rendering a sample presentation with multiple authors with affiliations and a corresponding author.

Success Criteria

You’ve successfully completed the exercise if you can:

  • Modify a Quarto/Pandoc partial template using conditionals and loops.
  • Display dynamic content based on YAML metadata.
  • Test and verify the output in a Reveal.js presentation.

Appendix: Typst Customisation (Optional)

Note

This section is optional supplementary material. It covers Typst customisation for participants interested in advanced PDF output.

Typst in Quarto

Typst is a modern typesetting system for creating beautiful PDFs, designed to be simpler than LaTeX.

Why Typst?

  • Fast - Instant PDF generation.
  • Simple - Markdown-like syntax.
  • Flexible - Easy template customisation.

See Typst Basics for more.

Typst Template Structure

Quarto’s Typst templates use two key files:

  • typst-template.typ - Defines document layout:
typst-template.typ
#let article(title: none, authors: none, body) = {
1  set page(paper: "a4", margin: 2.5cm)

2  set text(font: "Inter", size: 11pt)

3  if title != none {
    align(center, text(weight: "bold", 1.5em, title))
  }

4  body
}
1
Page setup.
2
Typography settings.
3
Conditional title block.
4
Main content insertion.
  • typst-show.typ - Captures YAML metadata using Pandoc syntax:
typst-show.typ
#show: doc => article(
  $if(title)$
  title: [$title$],
  $endif$
1  $if(by-author)$
  authors: [$for(by-author)$$it.name.literal$$sep$, $endfor$],
  $endif$
  doc,
)
1
Use by-author to get Quarto’s extended author metadata.
Note

Notice the Pandoc template syntax: $if()$, $for()$, $variable$.

Simple Customisation Example

typst-template.typ
#let article(
  title: none,
  body
) = {
  let primary = rgb("#2E86AB")
  
  if title != none {
    block(
      fill: primary,
      inset: 1em,
      radius: 0.5em,
      width: 100%
    )[
      #align(center)[
        #text(
          fill: white,
          weight: "bold",
          size: 1.5em,
          title
        )
      ]
    ]
  }
  
  body
}
typst-show.typ
#show: doc => article(
  $if(title)$
  title: [$title$],
  $endif$
  doc,
)

Screenshot of a PDF document with blue header titled Demo of Typst Format on white background with page number 1 at bottom

Creating a Typst Format

Step 1: Scaffold Extension

bash
quarto create extension format:typst my-format
cd my-format

This creates:

my-format
|-- README.md
|-- _extensions
|   `-- my-format
|       |-- _extension.yml
|       |-- typst-show.typ
|       `-- typst-template.typ
`-- template.qmd

2 directories, 5 files
Tip

Modify the generated typst-template.typ file to customise your layout.

Step 2: Integration with brand.yml

_brand.yml
color:
  primary: "#2E86AB"

logo:
  medium: "assets/logo.png"
typst-show.typ
#show: doc => article(
  $if(title)$
  title: [$title$],
  title_colour: brand-color.primary,
  $endif$
  doc,
)
page.typ
$if(logo)$
#set page(
  header: context {
    if counter(page).get().first() == 1{
      place(top + left, dy: 0.5cm, image("$logo.path$", width: 2cm))
    }
  }
)
$endif$
typst-template.typ
#let article(
  title: none,
  title_colour: "#000000",
  body
) = {
  set text(size: 11pt)
  if title != none {
    align(center)[
      #text(
        fill: rgb(title_colour),
        weight: "bold",
        size: 1.5em,
        title
      )
    ]
  }
  body
}

Hands-On Exercise: Creating a Format Extension

Exercise Overview

Objective: Create a custom format extension that bundles brand.yml and styling into a reusable format for your organisation.

Example Code: Exercises Typst

bash
tar -xzf "05c-exercises.tar.gz" -C "05-format-extension"

Part 1: Format Extension Setup

  1. Generate format extension scaffold:

    bash
    quarto create extension format:html company-report
    cd company-report
  2. Add brand.yml and configure extension in _extension.yml:

    yaml
    contributes:
      formats:
        typst:
          template-partials:
            - assets-typst/typst-template.typ
            - assets-typst/typst-show.typ
            - assets-typst/page.typ
      metadata:
        project:
          brand: brand.yml

Part 2: Customise and Test Your Format

  1. Define your template in typst-template.typ and typst-show.typ.

  2. Use your format in template.qmd:

    yaml
    ---
    title: "Quarterly Report"
    format: company-report-typst
    ---
  3. Render and verify:

    bash
    quarto render template.qmd

Part 3: Optional HTML Variant

Add HTML output to your format:

  1. Add HTML format to _extension.yml.

  2. Create/Modify simple template. (See HTML partials)

  3. Test both formats:

    bash
    quarto render template.qmd --to company-report-html
    quarto render template.qmd --to company-report-typst

Success Criteria

You’ve successfully completed the exercise if you can:

  • Create a working format extension with bundled branding.
  • Apply custom styling through brand.yml and SCSS.
  • Test the format with sample documents.
  • (Optional) Add HTML variant.
Back to top

Reuse