cynkra


Introducing cheetahR: A Lightning-Fast HTML Table widget for R

From the Blog
R
Tables
htmlWidgets

Author(s)

Olajoke Oladipo

Published

Say hello to cheetahR — the fastest way to explore massive datasets in R. Now available on CRAN, cheetahR is a high-performance table widget and a modern alternative to {reactable} and {DT}. Built for speed, it lets you interactively explore large datasets with smooth rendering and fully customizable layouts. Plus, it integrates seamlessly with Shiny, making it perfect for powerful, data-heavy dashboards.

As cheetahR is now available on CRAN! This post introduces the package, explains how it’s different from other table widgets, and provides a step-by-step guide to get started.

Hex Sticker of the R package cheetahR.

Why cheetahR?

R has great table widgets like {reactable} and {DT} — but when you need to render millions of rows blazingly fast, they can struggle.

That’s where cheetahR comes in. It wraps the ultra-fast JavaScript library Cheetah Grid in an R interface using {htmlwidgets}.

Key highlights:

  • Performance-first: Built for massive datasets
  • 🧩 Customizable: Define column settings easily
  • 🌐 Shiny-ready: Plug into dynamic dashboards

Installation

install.packages("cheetahR")

Or install the development version from GitHub:

# install.packages("devtools")
devtools::install_github("cynkra/cheetahR")

Getting Started

Let’s load the package

library(cheetahR)

Prepare a large dataset

bigdata <- do.call(rbind, rep(list(iris), 1000100 / nrow(iris)))
cheetah(bigdata)

This renders an interactive table with default settings. Smooth scrolling, no lag, and it works out-of-the-box.

Customize columns with column_def() using iris data

This demonstrates how to customize column properties (like width and display names) for each column in the iris dataset using the column_def() function in cheetahR. It’s a way to control how each column appears in the rendered table.

cheetah(
  iris,
  columns = list(
    Sepal.Length = column_def(name = "Sepal Length", width = 120),
    Sepal.Width = column_def(name = "Sepal Width", width = 120),
    Petal.Length = column_def(name = "Petal Length", width = 120),
    Petal.Width = column_def(name = "Petal Width", width = 120),
    Species = column_def(width = 100)
  )
)

Customize rownames

By default, rownames are displayed if present in the data. To customize the rownames column, provide the column definition with “rownames” as the column name.

cheetah(
  mtcars,
  columns = list(
    rownames = column_def(width = 150)
  )
)

Customize column styles

To enhance the appearance of your tables in cheetahR, you can customize column styles using the column_def() function. This allows you to define specific styles for individual columns, such as background color, font, and more. The style option must be a named list.

For example, to style the row names column with a light blue background and italicized, small-caps, bold Georgia font, you can use the following code:

cheetah(
  mtcars,
  columns = list(
    rownames = column_def(
      width = 150,
      style = list(
        bgColor = "#DFF",
        font = "italic small-caps bold 12px/30px Georgia, serif"
      )
    )
  )
)

This will render the row names column with the specified styles, enhancing the visual appeal of your table.

For more styling options, refer to the Cheetah Grid column styles documentation. This resource provides a comprehensive list of style properties you can apply to customize your tables further.

Customize the column types

You can change the way columns are displayed in cheetahR tables. For example, you can make a column show checkboxes instead of text, or format numbers differently. The example below shows how to turn the ‘am’ column into checkboxes.

data <- mtcars[, c(1:4, 9)] %>%
  mutate(
    am = if_else(am == 0, "true", "false")
  )

data %>%
  cheetah(
    columns = list(
      rownames = column_def(
        width = 150,
        style = list(
          bgColor = "#DFF",
          font = "italic small-caps bold 12px/30px Georgia, serif"
        )
      ),
      mpg = column_def(name = "Mile Per Gallon"),
      cyl = column_def(name = "Cylinders"),
      disp = column_def(name = "Displacement"),
      hp = column_def(name = "Horsepower"),
      am = column_def(
        name = "Automatic Transmission",
        column_type = "check",
        action = "check"
      )
    )
  )

Add cell messages

You can add informative messages to cells using add_cell_message(). This helps provide context or validation feedback to users. Here a few ways to make that happen:

Simple cell message

cheetah(
  data,
  columns = list(
    rownames = column_def(
      width = 150,
      style = list(
        bgColor = "#DFF",
        font = "italic small-caps bold 12px/30px Georgia, serif"
      )
    ),
    mpg = column_def(name = "Mile Per Gallon"),
    cyl = column_def(
      name = "Cylinders",
      style = list(textAlign = "center"),
      message = add_cell_message(type = "info", message = "Ok") # simple cell message
    ),
    disp = column_def(name = "Displacement"),
    hp = column_def(name = "Horsepower"),
    am = column_def(
      name = "Automatic Transmission",
      column_type = "check",
      action = "check"
    )
  )
)

Add conditional messages using js_ifelse()

The js_ifelse() function lets you show different messages depending on the cell value. It works like R’s ifelse() function, but behind the scenes it creates JavaScript code that checks the condition and returns the appropriate message.

# Insert empty strings to the first few entries
data$am[1:6] <- rep("", 6)

cheetah(
  data,
  columns = list(
    rownames = column_def(
      width = 150,
      style = list(
        bgColor = "#DFF",
        font = "italic small-caps bold 12px/30px Georgia, serif"
      )
    ),
    mpg = column_def(name = "Mile Per Gallon"),
    cyl = column_def(
      name = "Cylinders",
      style = list(textAlign = "center"),
      message = add_cell_message(type = "info", message = "Ok") # simple cell message
    ),
    disp = column_def(name = "Displacement"),
    hp = column_def(name = "Horsepower"),
    am = column_def(
      name = "Automatic Transmission",
      column_type = "check",
      action = "check",
      message = add_cell_message(
        message = js_ifelse(am, if_false = "Please check.") # Check the truthiness of a bare variable
      )
    )
  )
)

Usage in Shiny

cheetahR integrates with Shiny using cheetahOutput() in the UI and renderCheetah() in the server to display interactive data grids.

The full example of the cheetah table in shiny:

library(shiny)
library(bslib)
library(cheetahR)


ui <- page_fluid(cheetahOutput("grid"))

server <- function(input, output) {
  output$grid <- renderCheetah({
    cheetah(
      data,
      columns = list(
        rownames = column_def(
          width = 150,
          style = list(
            bgColor = "#DFF",
            font = "italic small-caps bold 12px/30px Georgia, serif"
          )
        ),
        mpg = column_def(name = "Mile Per Gallon"),
        cyl = column_def(
          name = "Cylinders",
          style = list(textAlign = "center"),
          message = add_cell_message(type = "info", message = "Ok") # simple cell message
        ),
        disp = column_def(name = "Displacement"),
        hp = column_def(name = "Horsepower"),
        am = column_def(
          name = "Automatic Transmission",
          column_type = "check",
          action = "check",
          message = add_cell_message(
            message = js_ifelse(am, if_false = "Please check.") # Check the truthiness of a bare variable
          )
        )
      )
    )
  })
}

shinyApp(ui = ui, server = server)

Learn More

What’s Next?

This is just v0.2.0. We’re planning:

  • Shiny proxy
  • More Shiny events and callbacks
  • Cell formating and cell indicator system
  • Pagination
  • More accessibility features

Want to contribute? Check out the GitHub issues!

Thanks for reading — and try cheetahR in your next data-heavy dashboard!