---
title: "Customizing your site"
code-annotations: hover
vignette: >
  %\VignetteIndexEntry{Customizing your site}
  %\VignetteEngine{quarto::html}
  %\VignetteEncoding{UTF-8}
---

If you want to customize your site, you can do so by editing
`_quartodown/_quartodown.yml`, which `quartodown::use_quartodown()` creates. The
`_quartodown/` folder at the package root also holds the files that [style the
site](#styling-and-layout). `_quartodown.yml` has nine fields, all optional:

- `url:` is the site's address, if it isn't the first `URL` in `DESCRIPTION`
  that isn't on GitHub, GitLab or Codeberg.
- `reference:` groups and orders the function reference index.
- `navbar:` lays out the navbar.
- `home:` picks the home page's source and lays out its sidebar.
- `authors:` links authors' names and picks who is shown where.
- `repo:` says where the source code is, if `DESCRIPTION` doesn't.
- `theme:` picks the light and dark themes.
- `redirects:` sends visitors from old addresses to new ones.
- `quarto:` changes any other Quarto setting.

## The reference index

Without `reference:`, the index lists every function in one section. To group
them, list the sections:

```yaml
reference:
  - title: Read and write              # <1>
    desc: Functions for getting data in and out.  # <2>
    contents:
      - read_data                      # <3>
      - starts_with("write_")          # <4>
  - title: Helpers
    subtitle: Low-level                # <5>
    contents:
      - has_concept("helpers")
      - -internal_helper               # <6>
```

1. Each entry becomes a section of the index, with this heading.
2. Optional Markdown text, shown under the heading.
3. A topic, by any of its `\alias{}` names or its Rd file name.
4. A selector.
5. An optional heading one level below `title`.
6. A leading `-` removes a topic.

The selectors are:

  | Selector                                              | Selects topics                                                                      |
  | ---                                                   | ---                                                                                 |
  | `starts_with("x")`, `ends_with("x")`, `contains("x")` | with an alias that starts with, ends with or contains `x`                           |
  | `matches("regex")`                                    | with an alias matching a regular expression                                         |
  | `has_concept("x")`, `has_keyword("x")`                | with that `\concept{}` or `\keyword{}`                                              |
  | `c(...)`                                              | selected by any of the selectors given                                              |
  | `-` before a topic or selector                        | removed from those the entries above select, or as the first entry, from all topics |

Topics that no section lists get a warning and are left off the index. The
exception is `\keyword{internal}` topics, which are left out, without a page,
unless named, as with roxygen's `reexports`, or selected with `internal = TRUE`,
as in `starts_with("dev_", internal = TRUE)`.

The format is the same as pkgdown's `reference:` field, so an existing one can
be copied over.

## The navbar

`navbar:` lists the items on the navbar's `left` and `right`, in order. The
default is:

```yaml
navbar:
  left: [intro, reference, articles, news]
  right: [repo]
```

Each of these is a keyword that quartodown turns into an item, and leaves out if
the package has nothing for it:

  | Keyword     | Item                                                                                                     |
  | ---         | ---                                                                                                      |
  | `intro`     | "Get started": the vignette named after the package, or the only top-level vignette if there's just one  |
  | `reference` | "Reference": the function reference index                                                                |
  | `articles`  | "Articles": a menu of every vignette no other item links, top-level ones first, then those in subfolders |
  | `news`      | "Changelog": `NEWS.md`                                                                                   |
  | `repo`      | The repository in `DESCRIPTION`'s `URL`, with a GitHub or GitLab icon (else a generic one)               |

Any other item is a vignette, given as its path relative to `vignettes/` without
extension and linked with its title, or a [Quarto navbar
item](https://quarto.org/docs/websites/website-navigation.html#top-navigation).
Inside a Quarto item's `menu:`, vignettes are given the same way, and a folder
ending in `/` lists every vignette in it.

For example, with the vignettes in a folder for each menu:

```yaml
navbar:
  left:
    - reference
    - news
    - text: Get started
      menu:
        - get-started/installation   # <1>
        - get-started/first-steps
    - text: User guide
      menu: user-guide/              # <2>
    - text: Developers
      menu:
        - dev/internals
        - text: Contributing         # <3>
          href: CONTRIBUTING.md
  right:
    - text: Blog
      href: https://example.com/blog
    - repo
```

1. `vignettes/get-started/installation.qmd`.
2. Every vignette in `vignettes/user-guide/`, sorted by file name.
3. Any Quarto navbar item works in a menu too.

Vignettes can live in any subfolder of `vignettes/`. Files and folders whose
name starts with `_` or `.` are skipped, as Quarto does.

Every vignette is built, even one the navbar doesn't link to. Such a vignette
can only be reached through links from other pages, so `build_site()` warns
about it, unless the navbar has `articles`, which lists every vignette nothing
else links.

::: {.callout-note}
R only builds top-level vignettes into the package, so vignettes in subfolders
are website-only.
:::

### A sidebar instead

With `style: sidebar`, the `left` items move into a sidebar beside every page,
and the navbar keeps the site's title, the search box and the `right` items:

```yaml
navbar:
  style: sidebar
```

Menus become sections of the sidebar, and "Reference" lists every reference page
by function name, with a section for each titled group of
[`reference:`](#the-reference-index).

## The home page

The home page shows `README.md`, or, if there is none, the package's description
from `DESCRIPTION`. To give the site a different home page than the README, use
`home: file:` at another file, relative to the package root:

```yaml
home:
  file: index.qmd
```

It can be Markdown (`.md`) or a Quarto document (`.qmd`), whose code runs when
the site is built, as in a vignette. Write links and image paths in it relative
to the package root, as in the README.

Next to the page, a sidebar shows the package's links, license, community files,
citation, authors and badges. `sidebar:` can reorder its sections, drop some, or
add your own, and `links:` adds to its links:

```yaml
home:
  links:
    - text: Blog
      href: https://example.com/blog
  sidebar:
    structure: [links, funding, license, authors]   # <1>
    components:
      funding:                                       # <2>
        title: Funding
        text: Supported by [a grant](https://example.com).
```

1. The sections, in order. The built-in ones are `links`, `license`,
   `community`, `citation`, `authors` and `dev` (the README's badges); by
   default, all of them in that order, then your own.
2. A section of your own: a heading and Markdown text.

For full control over the page you can turn the sidebar off with
`sidebar: false`:

```yaml
home:
  file: index.qmd
  sidebar: false
```

The page then shows the file as written. Like any other page, it then gets a
table of contents, which `toc: false` in its front matter can turn off.

## Authors

The home page's sidebar and the footer list the authors with the roles `aut`,
`cre` and `fnd` from `DESCRIPTION`'s `Authors@R`, and the authors page lists
everyone. `authors:` can link a person's name, or replace it with HTML such as a
logo, and change who is shown:

```yaml
authors:
  Jane Doe:                                # <1>
    href: https://jane.example.com
  Acme Inc:
    href: https://acme.example.com
    html: <img src="https://acme.example.com/logo.png" alt="Acme" height="24">
  sidebar:
    roles: [aut, cre]                      # <2>
    after: Thanks to all [contributors](authors.html).  # <3>
  footer:
    roles: [cre]
    text: Maintained by                    # <4>
```

1. A person, by their name as in `Authors@R`.
2. The roles shown in the sidebar.
3. Markdown shown under the sidebar's list, or with `before:` above it.
4. Instead of "Developed by".

The format is the same as pkgdown's `authors:`.

## The repository

Source links (the "Source:" line under each page's title), the sidebar's "Browse
source code", the navbar's repository icon and the changelog's `#123` and
`@user` links all come from the first GitHub, GitLab (including self-hosted, if
its host name has `gitlab` in it) or Codeberg URL in `DESCRIPTION`. For a
package in a folder of a repository, give the URL of the folder, with its
branch, as in `https://github.com/me/repo/tree/main/mypkg`.

`repo:` sets them where that isn't enough, such as for another host or branch:

```yaml
repo:
  url:
    home: https://git.sr.ht/~me/mypkg                # <1>
    source: https://git.sr.ht/~me/mypkg/tree/main/item/  # <2>
    issue: https://todo.sr.ht/~me/mypkg/             # <3>
    user: https://sr.ht/~                            # <4>
  branch: devel                                       # <5>
```

1. The repository's page.
2. Prefix of a file's link, such as `R/foo.R`.
3. Prefix of an issue's link, such as `123`.
4. Prefix of a user's link.
5. The branch the source links point to, instead of the default branch. Ignored
   when `source:` is set.

Each is optional and replaces only its own link. The format is the same as
pkgdown's `repo:`.

## Redirects

When a page moves, such as a function's reference page after it is renamed you
can use `redirects:` so links to the old address keeps working. Each entry is a
pair: the old address and the new one, both relative to the site's root:

```yaml
redirects:
  - ["reference/foo.bar.html", "reference/foo_bar.html"]
  - ["articles/old-guide.html", "vignettes/guide.html"]
```

For a vignette, Quarto's own
[`aliases:`](https://quarto.org/docs/websites/website-navigation.html#redirects)
in its front matter does the same.

## Other Quarto settings

quartodown writes a Quarto configuration into `_quarto/_quarto.yml` (overwritten
on every build). The `quarto:` field is merged over it, key by key:

- A list of entries, such as `website: navbar: left:`, is added to.
- Any other value is replaced.
- `~` removes a setting.

For example, to fold code blocks, drop the table of contents and change the
footer:

```yaml
quarto:
  format:
    html:
      code-fold: true
      toc: ~
  website:
    page-footer:
      right: "Built with love."
```

See the [Quarto website
reference](https://quarto.org/docs/reference/projects/websites.html) for the
full list of changes you can make.

`quarto:` applies to every page. To change a single vignette instead, set the
option in its front matter, which overrides the site-wide value:

```yaml
---
title: "A long tutorial"
format:
  html:
    code-fold: true
    toc-depth: 3
---
```

To change a single code chunk, use a chunk option such as `#| code-fold: true`.

## Styling and layout

The site uses Quarto's `default` theme in light mode and `darkly` in dark mode.
`theme:` picks others from Quarto's [built-in
themes](https://quarto.org/docs/output-formats/html-themes.html) (the Bootswatch
themes, as in pkgdown's `template: bootswatch:`), with quartodown's styling on
top:

```yaml
theme:
  light: flatly
  dark: darkly
```

Either can be left out to keep its default. A theme can also be your own `.scss`
file in `_quartodown/`, such as `light: _quartodown/brand.scss`. To adjust a
built-in theme you can use `extra.scss`, an example is given below.

::: {.callout-tip collapse="true"}
## A crowded navbar

Some themes space the navbar's items further apart or capitalize them. With
`lux`, for example, "Get started" wraps onto two lines and the version is cut
off. Bringing the items closer in `_quartodown/extra.scss` fixes it:

```scss
/*-- scss:rules --*/
.navbar .nav-item {
  margin-right: 0.25rem;
}

.navbar .nav-link,
.navbar-brand {
  white-space: nowrap;
}
```
:::

To restyle every page, add `_quartodown/extra.scss`. It is compiled on top of
quartodown's theme, once for the light theme and once for the dark one, and has
two parts: Bootstrap and Quarto
[variables](https://quarto.org/docs/output-formats/html-themes.html#sass-variables)
under `scss:defaults`, and CSS rules under `scss:rules`:

```scss
/*-- scss:defaults --*/
$primary: #2c7a7b;                       // <1>
$font-family-sans-serif: "Inter", sans-serif;

/*-- scss:rules --*/
.navbar {
  border-bottom: 1px solid $border-color; // <2>
}
```

1. Links, the active navbar item and buttons.
2. Variables take the value of the theme being compiled, so this suits both.

Plain CSS can go in `_quartodown/extra.css` instead, which is added to every
page as it is.

The page's widths and spacing are Quarto settings, under `quarto:`. For example,
a wider text column and table of contents:

```yaml
quarto:
  format:
    html:
      grid:
        body-width: 900px
        margin-width: 300px
```

See Quarto's [page
layout](https://quarto.org/docs/output-formats/page-layout.html) guide for
`grid:` and `page-layout:`.

The navbar's items start where the page's text does, which a script on each page
measures. To start them at the edge of the page instead, override it with:

```scss
/*-- scss:rules --*/
.navbar-container {
  padding-left: 1em !important;
}
```

Everything in `_quartodown/` is copied into the Quarto project, so other files
it holds can be named from `quarto:` by the same path, such as Quarto [template
partials](https://quarto.org/docs/journals/templates.html#template-partials):

```yaml
quarto:
  format:
    html:
      template-partials:
        - _quartodown/title-block.html
```

Setting `include-in-header:` or `include-after-body:` replaces quartodown's own
files, which, among other things, pick dark mode for visitors who prefer it and
line up the navbar. To add to them, list them too:

```yaml
quarto:
  format:
    html:
      include-in-header:
        - quartodown-header.html
        - _quartodown/analytics.html
```

## Coming from pkgdown

Moving a site over is very easy, and mostly means moving `_pkgdown.yml`'s
settings into `_quartodown/_quartodown.yml`. These have the same format, so can
be copied as is: `url:`, `reference:`, `home: sidebar:`, `home: links:`,
`authors:`, `repo:` and `redirects:`. The rest maps as follows:

  | pkgdown                         | quartodown                                                       |
  | ---                             | ---                                                              |
  | `navbar:`                       | lists items differently; see [The navbar](#the-navbar)           |
  | `articles:`                     | no equivalent: group vignettes with navbar menus instead         |
  | `home: title:`, `title:`        | `quarto: website: navbar: title:`                                |
  | `home: description:`            | `quarto: website: description:`                                  |
  | `lang:`                         | `quarto: lang:`                                                  |
  | `template: bootswatch:`         | [`theme: light:`](#styling-and-layout)                           |
  | `template: bslib:`              | `_quartodown/extra.scss`; fonts as below                         |
  | `template: opengraph:`          | `quarto: website: open-graph:` and `twitter-card:`, as below     |
  | `template: includes:`           | `quarto: format: html: include-in-header:` etc.                  |
  | `template: math-rendering:`     | `quarto: format: html: html-math-method:`                        |
  | `template: params: ganalytics:` | `quarto: website: google-analytics:`                             |
  | `template: light-switch:`       | always on: the site has a light and a dark theme                 |
  | `navbar: bg:`, `type:`          | `theme:` or `_quartodown/extra.scss`                             |
  | `toc: depth:`                   | `quarto: format: html: toc-depth:`                               |
  | `figures:`                      | `quarto: format: html: fig-width:`, `fig-height:`, `fig-dpi:`    |
  | `footer:`                       | `authors: footer:`, or `quarto: website: page-footer:`           |

A separate home page (an `index.md` used instead of the README) isn't picked up
automatically: set it with [`home: file:`](#the-home-page). Code that checks
`IN_PKGDOWN` (or `pkgdown::in_pkgdown()`) should check
`identical(Sys.getenv("IN_QUARTODOWN"), "true")` instead.

For example, this part of a `_pkgdown.yml`:

```yaml
template:
  bootswatch: flatly
  bslib:
    base_font: {google: "Inter"}
    code_font: {google: "Fira Code"}
  opengraph:
    twitter:
      creator: "@me"
      card: summary_large_image
home:
  title: "mypkg: Do Things"
  description: A package that does things.
```

becomes, in `_quartodown/_quartodown.yml`:

```yaml
theme:
  light: flatly
quarto:
  website:
    description: A package that does things.
    twitter-card:
      creator: "@me"
      card-style: summary_large_image
```

and, in `_quartodown/extra.scss`:

```scss
/*-- scss:defaults --*/
@import url("https://fonts.googleapis.com/css2?family=Inter&family=Fira+Code&display=swap");
$font-family-sans-serif: "Inter", sans-serif;
$font-family-monospace: "Fira Code", monospace;
```

A custom navbar item, such as a link to CRAN, is a Quarto navbar item:

```yaml
navbar:
  right:
    - repo
    - text: CRAN
      href: https://cran.r-project.org/package=mypkg
```

The rest works as with pkgdown, except that vignettes are published under
`vignettes/` rather than `articles/`: `articles/foo.html` becomes
`vignettes/foo.html`, and `articles/bar.html`, from
`vignettes/articles/bar.Rmd`, becomes `vignettes/articles/bar.html`. Likewise,
the changelog is `NEWS.html` rather than `news/index.html`. Update links to
them, or keep the old addresses working with [`redirects:`](#redirects).
