Skip to main content
AI in Production 2026 is now open for talk proposals.
Share insights that help teams build, scale, and maintain stronger AI systems.
items
Menu
  • About
    • Overview 
    • Join Us  
    • Community 
    • Contact 
  • Training
    • Overview 
    • Course Catalogue 
    • Public Courses 
  • Posit
    • Overview 
    • License Resale 
    • Managed Services 
    • Health Check 
  • Data Science
    • Overview 
    • Visualisation & Dashboards 
    • Open-source Data Science 
    • Data Science as a Service 
    • Gallery 
  • Engineering
    • Overview 
    • Cloud Solutions 
    • Enterprise Applications 
  • Our Work
    • Blog 
    • Case Studies 
    • R Package Validation 
    • diffify  

Sparklines in Reactable Tables in Shiny Apps

Author: Osheen MacOscar

Published: March 27, 2025

tags: r, sparkline, reactable, shiny

This is the third blog in a series about the {sparkline} R package for inline data visualisations. You can read the first one about getting started with the package here and the second one about embedding them in HTML tables with the {reactable} package here.

In this blog I am taking it a step further and demonstrating how to use our sparkline reactable table in a Shiny app. Thankfully {reactable} has some helpful functions that make this super easy! I will also look at using a dynamic traffic light image in a reactable table at the end.

Reactable Sparkline Table

I’m going to start where we ended the last blog. The following code creates a {reactable} table using the iris data with a few {sparkline} visualisations in the columns.

library(sparkline)
library(reactable)
library(dplyr)

data = tibble(
  names = c("x", "y", "z"),
  values = c(list(rnorm(10)), list(rnorm(10)), list(rnorm(10)))
  ) |>
  mutate(box = NA,
         line = NA,
         bar = NA)

table = reactable(data,
          columns = list(
            values = colDef(show = FALSE),
            box = colDef(cell = function(value, index) {
              sparkline(data$values[[index]], type = "box")
            }),
            line = colDef(cell = function(value, index) {
              sparkline(data$values[[index]], type = "line")
            }),
            bar = colDef(cell = function(value, index) {
              sparkline(data$values[[index]], type = "bar")
            })
          )
        )

Data comes in all shapes and sizes. It can often be difficult to know where to start. Whatever your problem, Jumping Rivers can help.

Using sparklines in a Shiny App

This is actually made very easy by two {reactable} functions which follow the traditional Shiny naming. In our server we’ll need to use renderReactable (which uses htmlwidgets::shinyRenderWidget under the hood), to create our table in the server. Then in the UI we’ll use reactableOutput (which uses htmlwidgets::shinyWidgetOutput) to call our table in the app UI.

To demonstrate this I am using a basic shiny app with a sparkline bullet chart in a reactable table then a screenshot of the result.

# Server
library(shiny)

server <- function(input, output) {

  output$sparkline_table <- renderReactable({

  data = iris |>
    group_by(.data$Species) |>
    mutate(mean = mean(.data$Sepal.Length),
           lower_range = range(.data$Sepal.Length)[1],
           upper_range = range(.data$Sepal.Length)[2],
           bullet = NA) 

  iris_table = reactable(
    d,
    defaultColDef = colDef(show = FALSE),
    columns = list(
      Species = colDef(show = TRUE),
      Sepal.Length = colDef(show = TRUE),
      bullet = colDef(
        cell = function(value, index) {
          sparkline(c(d$mean[[index]],
                      d$Sepal.Length[[index]],
                      d$upper_range[[index]],
                      d$lower_range[[index]]),
                    type = "bullet")
        },
        show = TRUE
      )
    )
  )
  })
}
# UI
ui <- fluidPage(
  
  titlePanel("Hello Sparkline!"),
  
  sidebarLayout(
    sidebarPanel = sidebarPanel(
      sliderInput(inputId = "rows",
                  label = "Number of rows:",
                  min = 1,
                  max = 50,
                  value = 30)
    ),
    
    mainPanel = mainPanel(
      
      reactableOutput(outputId = "sparkline_table")
      
  ))
)

Shiny app with sparkline reactable table.

Dynamic Image in a Reactable Table

Another thing that you can do with {reactable} is dynamic image columns, to show this I’ve created a traffic light visualisation with 3 levels:

Level 1 (green): Level 1 (green) traffic light.

Level 2 (Amber): Level 2 (Amber) traffic light.

Level 3 (Red): Level 3 (Red) traffic light.

For this example I’m only going to include the code required to create the {reactable} table but following the steps above will work for a shiny app as well, ensuring that the images are available to the app at the path you pass to the table.

The key here is to use a reactable column definition which is a function. This function will take the value and create a html image tag with the path to the correct svg file (png and jpeg will work the same).

library(tibble)
library(htmltools)
library(reactable)

data <- tibble(
    Value = 1:3,
  `Traffic Light` = 1:3
)

path = "/blog/sparkline-reactable-shiny/images/"

table = 
  reactable(data, 
            defaultColDef = colDef(align = "center"),
            columns = list(`Traffic Light` = colDef(
              cell = function(value) {
                src = paste0(path, value, ".svg")
                image = img(src = src, style = "height: 40px;")
                tagList(
                  div(
                    style = "display: inline-block; width: 60px",
                    image)
                  )
                })
              )
            )

In this blog we have looked at embedding sparkline reactable tables into a shiny app and using another type of dynamic image inside a reactable table. This brings me to the end of the series on {sparkline}, with a notable cameo from {reactable} and a bit of {shiny} too. Stay tuned for similar data science blogs.


Jumping Rivers Logo

Recent Posts

  • Start 2026 Ahead of the Curve: Boost Your Career with Jumping Rivers Training 
  • Should I Use Figma Design for Dashboard Prototyping? 
  • Announcing AI in Production 2026: A New Conference for AI and ML Practitioners 
  • Elevate Your Skills and Boost Your Career – Free Jumping Rivers Webinar on 20th November! 
  • Get Involved in the Data Science Community at our Free Meetups 
  • Polars and Pandas - Working with the Data-Frame 
  • Highlights from Shiny in Production (2025) 
  • Elevate Your Data Skills with Jumping Rivers Training 
  • Creating a Python Package with Poetry for Beginners Part2 
  • What's new for Python in 2025? 

Top Tags

  • R (236) 
  • Rbloggers (182) 
  • Pybloggers (89) 
  • Python (89) 
  • Shiny (63) 
  • Events (26) 
  • Training (23) 
  • Machine Learning (22) 
  • Conferences (20) 
  • Tidyverse (17) 
  • Statistics (14) 
  • Packages (13) 

Authors

  • Amieroh Abrahams 
  • Shane Halloran 
  • Russ Hyde 
  • Myles Mitchell 
  • Tim Brock 
  • Theo Roe 
  • Colin Gillespie 
  • Aida Gjoka 
  • Gigi Kenneth 
  • Osheen MacOscar 
  • Sebastian Mellor 
  • Keith Newman 
  • Pedro Silva 

Keep Updated

Like data science? R? Python? Stan? Then you’ll love the Jumping Rivers newsletter. The perks of being part of the Jumping Rivers family are:

  • Be the first to know about our latest courses and conferences.
  • Get discounts on the latest courses.
  • Read news on the latest techniques with the Jumping Rivers blog.

We keep your data secure and will never share your details. By subscribing, you agree to our privacy policy.

Follow Us

  • GitHub
  • Bluesky
  • LinkedIn
  • YouTube
  • Eventbrite

Find Us

The Catalyst Newcastle Helix Newcastle, NE4 5TG
Get directions

Contact Us

  • hello@jumpingrivers.com
  • + 44(0) 191 432 4340

Newsletter

Sign up

Events

  • North East Data Scientists Meetup
  • Leeds Data Science Meetup
  • Shiny in Production
British Assessment Bureau, UKAS Certified logo for ISO 9001 - Quality management British Assessment Bureau, UKAS Certified logo for ISO 27001 - Information security management Cyber Essentials Certified Plus badge
  • Privacy Notice
  • |
  • Booking Terms

©2016 - present. Jumping Rivers Ltd