The fmt_url() function

Using a portion of the towny dataset, let’s create a gt table. We can use fmt_url() on the website column to generate navigable links to websites. By default the links are underlined and the color will be chosen for you (it’s dark cyan).

towny |>
  dplyr::filter(csd_type == "city") |>
  dplyr::arrange(desc(population_2021)) |>
  dplyr::select(name, website, population_2021) |>
  dplyr::slice_head(n = 10) |>
  gt() |>
  tab_header(
    title = md("The 10 Largest Municipalities in `towny`"),
    subtitle = "Population values taken from the 2021 census."
  ) |>
  fmt_integer() |>
  fmt_url(columns = website) |>
  cols_label(
    name = "Name",
    website = "Site",
    population_2021 = "Population"
  )
The 10 Largest Municipalities in towny
Population values taken from the 2021 census.
Name Site Population
Toronto https://www.toronto.ca 2,794,356
Ottawa https://ottawa.ca 1,017,449
Mississauga https://www.mississauga.ca 717,961
Brampton https://www.brampton.ca 656,480
Hamilton https://www.hamilton.ca 569,353
London https://london.ca 422,324
Markham https://www.markham.ca 338,503
Vaughan https://www.vaughan.ca 323,103
Kitchener https://www.kitchener.ca 256,885
Windsor https://www.citywindsor.ca 229,660

Let’s try something else. We can set a static text label for the link with the label argument (and we’ll use the word "site" for this). The link underline is removable with show_underline = FALSE. With this change, it seems sensible to merge the link to the "name" column and enclose the link text in parentheses (cols_merge() handles all that).

towny |>
  dplyr::filter(csd_type == "city") |>
  dplyr::arrange(desc(population_2021)) |>
  dplyr::select(name, website, population_2021) |>
  dplyr::slice_head(n = 10) |>
  gt() |>
  tab_header(
    title = md("The 10 Largest Municipalities in `towny`"),
    subtitle = "Population values taken from the 2021 census."
  ) |>
  fmt_integer() |>
  fmt_url(
    columns = website,
    label = "site",
    show_underline = FALSE
  ) |>
  cols_merge(
    columns = c(name, website),
    pattern = "{1} ({2})"
  ) |>
  cols_label(
    name = "Name",
    population_2021 = "Population"
  )
The 10 Largest Municipalities in towny
Population values taken from the 2021 census.
Name Population
Toronto (site) 2,794,356
Ottawa (site) 1,017,449
Mississauga (site) 717,961
Brampton (site) 656,480
Hamilton (site) 569,353
London (site) 422,324
Markham (site) 338,503
Vaughan (site) 323,103
Kitchener (site) 256,885
Windsor (site) 229,660

fmt_url() allows for the styling of links as ‘buttons’. This is as easy as setting as_button = TRUE. Doing that unlocks the ability to set a button_fill color. This color can automatically selected by gt (this is the default) but here we’re using "steelblue". The label argument also accepts a function! We can choose to adapt the label text from the URLs by eliminating any leading "https://" or "www." parts.

towny |>
  dplyr::filter(csd_type == "city") |>
  dplyr::arrange(desc(population_2021)) |>
  dplyr::select(name, website, population_2021) |>
  dplyr::slice_head(n = 10) |>
  dplyr::mutate(ranking = dplyr::row_number()) |>
  gt(rowname_col = "ranking") |>
  tab_header(
    title = md("The 10 Largest Municipalities in `towny`"),
    subtitle = "Population values taken from the 2021 census."
  ) |>
  fmt_integer() |>
  fmt_url(
    columns = website,
    label = function(x) gsub("https://|www.", "", x),
    as_button = TRUE,
    button_fill = "steelblue",
    button_width = px(150)
  ) |>
  cols_move_to_end(columns = website) |>
  cols_align(align = "center", columns = website) |>
  cols_width(
    ranking ~ px(40),
    website ~ px(200)
  ) |>
  tab_options(column_labels.hidden = TRUE) |>
  tab_style(
    style = cell_text(weight = "bold"),
    locations = cells_stub()
  ) |>
  opt_vertical_padding(scale = 0.75)
The 10 Largest Municipalities in towny
Population values taken from the 2021 census.
1 Toronto 2,794,356 toronto.ca
2 Ottawa 1,017,449 ottawa.ca
3 Mississauga 717,961 mississauga.ca
4 Brampton 656,480 brampton.ca
5 Hamilton 569,353 hamilton.ca
6 London 422,324 london.ca
7 Markham 338,503 markham.ca
8 Vaughan 323,103 vaughan.ca
9 Kitchener 256,885 kitchener.ca
10 Windsor 229,660 citywindsor.ca

It’s perhaps inevitable that you’ll come across missing values in your column of URLs. fmt_url() will preserve input NA values, allowing you to handle them with sub_missing(). Here’s an example of that.

towny |>
  dplyr::arrange(population_2021) |>
  dplyr::select(name, website, population_2021) |>
  dplyr::slice_head(n = 10) |>
  gt() |>
  tab_header(
    title = md("The 10 Smallest Municipalities in `towny`"),
    subtitle = "Population values taken from the 2021 census."
  ) |>
  fmt_integer() |>
  fmt_url(columns = website) |>
  cols_label(
    name = "Name",
    website = "Site",
    population_2021 = "Population"
  ) |>
  sub_missing()
The 10 Smallest Municipalities in towny
Population values taken from the 2021 census.
Name Site Population
Cockburn Island https://cockburnisland.ca 16
Thornloe 92
Brethour 105
Gauthier 151
Mattawan https://mattawan.ca 153
Hilton Beach https://hiltonbeach.com 198
Opasatika https://www.opasatika.net 200
Hilliard https://townshipofhilliard.ca 215
Pelee https://www.pelee.org 230
Head, Clara and Maria https://www.townshipsofheadclaramaria.ca 267

Links can be presented as icons. Let’s take a look at an example of this type of presentation with a table based on the films dataset. The imdb_url column contains the URL information and in the fmt_url() call, we can use fontawesome::fa() to specify a label. In this case we elect to use the "link" icon and we can make some sizing adjustments to the icon here to ensure the layout looks optimal. We also use cols_merge() to combine the film’s title, its original title (if present), and the link icon.

films |>
  dplyr::filter(year == 2021) |>
  dplyr::select(
    contains("title"), run_time, director, imdb_url
  ) |>
  gt() |>
  tab_header(title = "Feature Films in Competition at the 2021 Festival") |>
  fmt_url(
    columns = imdb_url,
    label = fontawesome::fa(
      name = "link",
      height = "0.75em",
      vertical_align = "0em"
     ),
    color = "gray65"
  ) |>
  cols_merge(
    columns = c(title, original_title, imdb_url),
    pattern = "{1}<< ({2})>> {3}"
  ) |>
  cols_label(
    title = "Film",
    run_time = "Length",
    director = "Director(s)",
  ) |>
  tab_options(heading.title.font.size = px(26)) |>
  opt_vertical_padding(scale = 0.4) |>
  opt_horizontal_padding(scale = 2) |>
  opt_align_table_header(align = "left")
Feature Films in Competition at the 2021 Festival
Film Length Director(s)
The Story of My Wife (A feleségem története) 2h 49m Ildikó Enyedi
Annette 2h 21m Leos Carax
Benedetta 2h 11m Paul Verhoeven
Bergman Island 1h 52m Mia Hansen-Løve
Drive My Car (Doraibu mai kâ) 2h 59m Ryûsuke Hamaguchi
Flag Day 1h 49m Sean Penn
France 2h 13m Bruno Dumont
A Hero (Ghahreman) 2h 7m Asghar Farhadi
Ahed's Knee (Ha'berech) 1h 49m Nadav Lapid
Casablanca Beats (Haut et fort) 1h 41m Nabil Ayouch
Compartment Number 6 (Hytti nro 6) 1h 47m Juho Kuosmanen
The Divide (La fracture) 1h 38m Catherine Corsini
The Restless (Les intranquilles) 1h 57m Joachim Lafosse
Paris, 13th District (Les Olympiades, Paris 13e) 1h 45m Jacques Audiard
Lingui 1h 27m Mahamat-Saleh Haroun
Memoria 2h 16m Apichatpong Weerasethakul
Nitram 1h 52m Justin Kurzel
Petrov's Flu (Petrovy v grippe) 2h 25m Kirill Serebrennikov
Red Rocket 2h 10m Sean Baker
The French Dispatch 1h 47m Wes Anderson
Titane 1h 48m Julia Ducournau
Everything Went Fine (Tout s'est bien passé) 1h 53m François Ozon
Three Floors (Tre piani) 1h 59m Nanni Moretti
The Worst Person in the World (Verdens verste menneske) 2h 8m Joachim Trier