Great Tables can render a fully interactive table (with sorting, searching, filtering, and pagination) by calling opt_interactive(). The result is a self-contained HTML widget powered by DataTables that works in Jupyter notebooks, Quarto documents, and any HTML output.
Enabling interactivity
A single call to opt_interactive() switches the table from static to interactive. All of the normal formatting and styling methods continue to work exactly as before.
from great_tables import GT
from great_tables.data import gtcars
import polars as pl
gtcars_pl = pl.from_pandas(gtcars).select(["mfr", "model", "year", "hp", "trq", "msrp"])
(
GT(gtcars_pl)
.tab_header(title="GT Cars", subtitle="The full dataset, interactively")
.cols_label(mfr="Make", model="Model", year="Year", hp="HP", trq="Torque", msrp="MSRP")
.fmt_integer(columns=["year", "hp", "trq"], use_seps=False)
.fmt_currency(columns="msrp")
.opt_interactive()
)
Click on any column header to sort. The table is paginated by default with 10 rows per page.
Search and per-column filters
Pass use_search=True to add a global search box, and use_filters=True to add a per-column text filter row beneath the headers.
from great_tables import GT
from great_tables.data import gtcars
import polars as pl
(
GT(gtcars_pl)
.tab_header(title="GT Cars: Search and Filter")
.cols_label(mfr="Make", model="Model", year="Year", hp="HP", trq="Torque", msrp="MSRP")
.fmt_integer(columns=["year", "hp", "trq"], use_seps=False)
.fmt_currency(columns="msrp")
.opt_interactive(use_search=True, use_filters=True)
)
Try typing "Audi" in the Make filter or "2017" in the Year filter to narrow the results.
The tab_style() methods works in interactive mode for loc.body() and loc.column_labels(). Styles are applied row-by-row as DataTables renders each page, so they follow the data when you sort or filter.
from great_tables import style, loc
(
GT(gtcars_pl)
.tab_header(title="GT Cars: Targeted styles")
.cols_label(mfr="Make", model="Model", year="Year", hp="HP", trq="Torque", msrp="MSRP")
.fmt_integer(columns=["year", "hp", "trq"], use_seps=False)
.fmt_currency(columns="msrp")
.tab_style(
style=style.fill(color="#fff3cd"),
locations=loc.body(columns="hp", rows=pl.col("hp") > 500),
)
.tab_style(
style=[style.text(color="#c0392b", weight="bold")],
locations=loc.body(columns="msrp", rows=pl.col("msrp") > 200_000),
)
.tab_style(
style=[style.fill(color="#ddeeff"), style.text(weight="bold")],
locations=loc.column_labels(columns=["hp", "trq"]),
)
.opt_interactive(use_search=True, use_filters=True, page_size_default=10)
)
From the output you might notice:
- rows where HP exceeds 500 are highlighted in amber
- MSRP values over $200,000 appear in bold red
- the
HP and Torque column headers have a blue-tinted background
Sort by HP or MSRP to confirm that the styling moves with the data.
The use of data_color() is fully supported in interactive tables. It applies a continuous color scale to each cell based on the underlying value. Because data_color() is implemented via tab_style() internally, it inherits the same interactive behavior automatically.
(
GT(gtcars_pl)
.tab_header(title="GT Cars: data_color()")
.cols_label(mfr="Make", model="Model", year="Year", hp="HP", trq="Torque", msrp="MSRP")
.fmt_integer(columns=["year", "hp", "trq"], use_seps=False)
.fmt_currency(columns="msrp")
.data_color(columns="hp", palette=["#fff7ec", "#ef6c00"])
.data_color(columns="msrp", palette="Blues")
.opt_interactive(use_search=True, use_filters=True, page_size_default=10)
)
Each column uses its own independent scale: orange for HP and blue for MSRP. Try filtering by Make to see how the scales update in context.
Multiple columns, shared scale
Pass domain= to lock the color range across columns so they share a common scale.
(
GT(gtcars_pl)
.tab_header(
title="GT Cars: HP and Torque on a shared scale",
subtitle="Higher values are darker and both columns use the same domain",
)
.cols_label(mfr="Make", model="Model", year="Year", hp="HP", trq="Torque", msrp="MSRP")
.fmt_integer(columns=["year", "hp", "trq"], use_seps=False)
.fmt_currency(columns="msrp")
.data_color(
columns=["hp", "trq"],
palette=["#edf8fb", "#006d2c"],
domain=[200, 700],
)
.opt_interactive(use_search=True, page_size_default=10)
)