---
title: "Headings and text"
output: rmarkdown::html_vignette
vignette: >
%\VignetteIndexEntry{Headings and text}
%\VignetteEngine{knitr::rmarkdown}
%\VignetteEncoding{UTF-8}
---
```{r, include = FALSE}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>"
)
library(shinyGovstyle)
```
## Overview
This vignette covers all functions in shinyGovstyle that produce styled text content: headings, body text, lists, callout components, links, and typography. For page structure and layout, see the [Layout options](layout-options.html) vignette.
---
## `heading_text()`
Creates a semantic HTML heading element with a GOV.UK heading CSS class.
```{r, eval = FALSE}
heading_text("Summary", size = "l", level = 2)
```
### Arguments
| Argument | Default | Description |
|---|---|---|
| `text_input` | — | The heading text to display |
| `size` | `"xl"` | Visual size: `"xl"`, `"l"`, `"m"`, or `"s"` |
| `level` | `1` | HTML heading level: integer 1–6 |
| `id` | auto | Element ID — auto-generated from `text_input` if omitted |
### Visual size and semantic level are independent
`size` controls the CSS class applied (`govuk-heading-xl`, `govuk-heading-l`, etc.), which determines how the heading looks. `level` controls the HTML element used (`
`, ``, etc.), which determines its position in the document outline read by screen readers and assistive technologies.
These are independent because it is occasionally necessary to use a smaller visual heading at a higher semantic level, or vice versa. For example, a page where the first visible heading needs to be modest in size but is still structurally the ``:
```{r, eval = FALSE}
heading_text("User guide", size = "m", level = 1)
```
Always set both arguments deliberately. Do not leave `level` at its default of `1` for every heading on a page.
### Recommended size–level pairings
**Standard pages** (most dashboards and data tools):
| Heading role | `size` | `level` |
|---|---|---|
| Page title | `"l"` | `1` |
| Section heading | `"m"` | `2` |
| Sub-section heading | `"s"` | `3` |
**Long-form content** (user guides, methodology, accessibility statements):
| Heading role | `size` | `level` |
|---|---|---|
| Page title | `"xl"` | `1` |
| Section heading | `"l"` | `2` |
| Sub-section heading | `"m"` | `3` |
| Sub-sub-section heading | `"s"` | `4` |
### Accessibility
**Do not skip heading levels.** Moving from an `` straight to an `` breaks the document outline and makes it harder for screen reader users to navigate, as they commonly jump between headings to scan a page. This is a requirement under [WCAG 2.2 success criterion 1.3.1: Info and Relationships](https://www.w3.org/WAI/WCAG22/Understanding/info-and-relationships).
**Write headings in sentence case.** Only capitalise the first word and proper nouns.
```{r, eval = FALSE}
# Correct — sentence case
heading_text("Summary of findings", size = "l", level = 1)
# Incorrect — title case
heading_text("Summary Of Findings", size = "l", level = 1)
```
For more information, read the [GOV.UK headings guidance](https://design-system.service.gov.uk/styles/headings/).
### Heading IDs
If `id` is not supplied it is auto-generated by lowercasing `text_input` and replacing non-alphanumeric characters with underscores. Supply an explicit `id` when you need a stable anchor to link to, or when two headings would otherwise generate the same ID:
```{r, eval = FALSE}
heading_text("Methodology", size = "l", level = 2, id = "methodology")
```
---
## `gov_text()`
A wrapper that produces a `
` paragraph element. Use it when you want to add body text with correct GOV.UK styling without writing raw tag calls.
```{r, eval = FALSE}
gov_box(
size = "two-thirds",
gov_text("This is a paragraph of body text.")
)
```
---
## `gov_list()`
Creates a GOV.UK-styled list. The `style` argument controls both the HTML element used and the visual presentation:
| `style` | HTML element | Appearance |
|---|---|---|
| `"none"` (default) | `
` | Plain, no markers |
| `"bullet"` | `` | Bulleted list |
| `"number"` | `` | Numbered list |
```{r, eval = FALSE}
gov_list(c("First item", "Second item", "Third item"), style = "bullet")
gov_list(c("First step", "Second step", "Third step"), style = "number")
```
Use `style = "number"` when order matters — steps in a process, ranked results, or sequential instructions. Use `style = "bullet"` for unordered items. The plain style (`"none"`) is useful when you want list semantics for screen readers without a visual marker.
For more information, read the [GOV.UK lists guidance](https://design-system.service.gov.uk/styles/lists/).
---
## `insert_text()`
Displays a GOV.UK inset text box — a bordered callout for supplementary information that is related to, but not the main focus of, the surrounding content.
```{r, eval = FALSE}
insert_text(
inputId = "processing-note",
text = "It can take up to 8 weeks to process your application."
)
```
Use inset text for information the user needs to know but that is not the primary action or decision on the page — for example, a processing time, an exception to a rule, or a clarification. Do not use it for warnings about consequences; use `warning_text()` instead.
For more information, read the [GOV.UK inset text guidance](https://design-system.service.gov.uk/components/inset-text/).
---
## `warning_text()`
Displays a GOV.UK warning text component: a bold statement with a prominent "!" icon, used to warn users about something with serious consequences.
```{r, eval = FALSE}
warning_text(
inputId = "fine-warning",
text = "You can be fined up to £5,000 if you do not register."
)
```
The "!" icon carries `aria-hidden = "true"` and the word "Warning" is prepended as visually hidden text, so screen readers announce "Warning: [your text]" without reading out the icon character. Given this, you should avoid starting the text with 'Warning', else you'll submit users to 'Warning Warning'.
Use `warning_text()` when the consequence of missing the information is serious. For less critical supplementary information, use `insert_text()` instead.
For more information, read the [GOV.UK warning text guidance](https://design-system.service.gov.uk/components/warning-text/).
---
## `noti_banner()`
Displays a GOV.UK notification banner for information that is not directly related to the current page content — such as a service-wide problem, an upcoming deadline, or the outcome of a previous action.
### Two types
**Standard** (default, blue): for neutral information such as service problems or upcoming events.
```{r, eval = FALSE}
noti_banner(
inputId = "service-notice",
title_txt = "Important",
body_txt = paste0(
"This service will be unavailable on Saturday ",
"14 June from 8am to 6pm."
)
)
```
**Success** (green): to confirm that a previous action completed successfully. Uses `role="alert"` so screen readers announce it automatically on page load.
```{r, eval = FALSE}
noti_banner(
inputId = "submission-confirm",
title_txt = "Success",
body_txt = "Your report has been submitted.",
type = "success"
)
```
### When to use each component
| Situation | Component |
|---|---|
| Information not related to the current page task | `noti_banner()` |
| Supplementary information related to the page | `insert_text()` |
| Serious consequences if the user misses information | `warning_text()` |
| Form validation errors | `error_summary()` / error messages |
Use notification banners sparingly — users often overlook them when they appear frequently. Show only one at a time, and never alongside an error summary.
For more information, read the [GOV.UK notification banner guidance](https://design-system.service.gov.uk/components/notification-banner/).
---
## `external_link()`
A wrapper for HTML anchor elements that produces safe, accessible external links with consistent behaviour.
```{r, eval = FALSE}
external_link("https://www.example.gov.uk/guidance", "Guidance for applicants")
```
### What the function does automatically
- Adds `target="_blank"` to open the link in a new tab
- Adds `rel="noopener noreferrer"` to prevent [reverse tabnabbing](https://owasp.org/www-community/attacks/Reverse_Tabnabbing)
- Appends "(opens in new tab)" to the visible link text by default
- Adds a visually hidden "(opens in new tab)" span for screen readers when `add_warning = FALSE`
### Descriptive link text
The function validates `link_text` and will error if you supply a raw URL as the link text, vague text such as "click here" or "here", or text ending with a full stop. It will also warn if the text is fewer than 7 characters.
This enforces [WCAG 2.2 success criterion 2.4.4: Link Purpose (In Context)](https://www.w3.org/WAI/WCAG22/Understanding/link-purpose-in-context), which requires link text to describe the destination without needing the surrounding context to make sense of it.
```{r, eval = FALSE}
# Correct — descriptive
external_link("https://www.example.gov.uk/apply", "Apply for a licence")
# Will error — vague text
external_link("https://www.example.gov.uk/apply", "click here")
# Will error — raw URL as text
external_link(
"https://www.example.gov.uk/apply",
"https://www.example.gov.uk/apply"
)
```
### Grouped links
When displaying several external links together, repeating "(opens in new tab)" on each is visually repetitive. Set `add_warning = FALSE` and add a single explanatory sentence above the group instead:
```{r, eval = FALSE}
gov_text("The following links open in a new tab.")
shiny::tags$ul(
shiny::tags$li(
external_link(
"https://www.example.gov.uk/a",
"Guidance document A",
add_warning = FALSE
)
),
shiny::tags$li(
external_link(
"https://www.example.gov.uk/b",
"Guidance document B",
add_warning = FALSE
)
)
)
```
For more information, read the [GOV.UK links guidance](https://design-system.service.gov.uk/styles/links/).
---
## `font()`
GDS Transport is a restricted typeface and **must only be used on GOV.UK domains**. If your app is not hosted on a GOV.UK domain, do not call `font()`. You do not need to do anything and your app will default to Arial instead, which is the correct behaviour.
If you are on a GOV.UK domain and therefore want to use the `font()` function, putting it within your UI will load the GDS Transport typeface for use in your app. By default the GOV.UK Frontend CSS specifies `font-family: GDS Transport, arial, sans-serif` — if the font files are not loaded the browser falls back to Arial automatically.
```{r, eval = FALSE}
# Only include this if your app is on a GOV.UK domain
font()
```
For more information on when GDS Transport is permitted, read the [GOV.UK typeface guidance](https://design-system.service.gov.uk/styles/typeface/).