The Component Workshop: Reflex's 100 Library Components
·
Course overview
Layout
·
Box
·
Flex
·
Stack
·
Grid
·
Container
·
Section
·
Center
·
Spacer
·
Separator
·
Card
·
Inset
·
Aspect Ratio
·
Fragment
Typography
·
Text
·
Heading
·
Link
·
Code
·
Markdown
·
Blockquote
·
Quote
·
Strong
·
Em
·
Kbd
Forms
·
Button
·
Input
·
Text Area
·
Checkbox
·
Switch
·
Radio Group
·
Select
·
Slider
·
Form
·
Upload
Data display
·
Badge
·
Avatar
·
Icon
·
Callout
·
List
·
Data List
·
Code Block
·
Progress
·
Spinner
·
Scroll Area
·
Moment
Disclosure
·
Tabs
·
Accordion
·
Segmented Control
Overlay
·
Tooltip
·
Popover
·
Hover Card
·
Dialog
·
Alert Dialog
·
Drawer
·
Dropdown Menu
·
Context Menu
·
Toast
Dynamic rendering
·
Cond
·
Match
·
Foreach
·
Auto Scroll
Media
·
Image
·
Audio
·
Video
Tables and data grids
·
Table
·
Data Table
·
Data Editor
Charts
·
Area Chart
·
Bar Chart
·
Line Chart
·
Composed Chart
·
Pie Chart
·
Radar Chart
·
Radial Bar Chart
·
Scatter Chart
·
Funnel Chart
·
Treemap
·
Sankey Chart
·
Error Bar
Chart parts
·
Axis
·
Cartesian Grid
·
Chart Tooltip
·
Legend
·
Label
·
Reference
·
Brush
Other chart libraries
·
Plotly
·
Pyplot
HTML elements
·
HTML
·
HTML Text
·
HTML Layout
·
HTML Forms
·
HTML Media
·
HTML Tables
·
SVG
Other tools
·
Theme
·
Skeleton
·
Clipboard
·
Html Embed
·
Script
·
Memo
Workshop order
Please show last month's visitors by browser as a donut, with the name and value visible for each slice.
rx.recharts.pie_chart treats the whole as 100 and divides it into slices showing each part's share. Use it when there are no more than five or six slices and "how much of the whole" is what matters. Unlike other charts, data goes on rx.recharts.pie, not on the chart container. data_key is the slice size and name_key is the slice name.
Put "fill" in a dict of the data and only that slice takes that color; otherwise the fill of pie is used.
rx.recharts.pie_chart(
rx.recharts.pie(
data=[
{"name": "Group A", "value": 400},
{"name": "Group B", "value": 300, "fill": rx.color("teal", 9)},
{"name": "Group C", "value": 300, "fill": rx.color("orange", 9)},
{"name": "Group D", "value": 200, "fill": rx.color("plum", 9)},
],
data_key="value",
name_key="name",
fill=rx.color("accent", 9),
label=True,
),
width="100%",
height=300,
)Make inner_radius greater than 0 and the pie becomes a donut with a hollow center. Radii take a number (pixels) or a percentage string.
Try the props
inner_radius
outer_radius
color
label
label_line
legend_type
rx.recharts.pie_chart(
rx.recharts.pie(
data=[
{"name": "Chrome", "value": 275},
{"name": "Safari", "value": 150},
{"name": "Firefox", "value": 100},
{"name": "Edge", "value": 130},
],
data_key="value",
name_key="name",
inner_radius="0%",
outer_radius="80%",
fill=rx.color("indigo", 8),
stroke=rx.color("gray", 1),
label=True,
label_line=True,
legend_type="rect",
),
rx.recharts.graphing_tooltip(),
rx.recharts.legend(),
width="100%",
height=300,
)| Prop | Values | Default | Use |
|---|---|---|---|
pie_chart(width=, height=, margin=) | number or percentage / dict | "100%" | Chart size and margin. data does not go here |
pie(data=) | list of dicts | none | Slice data |
pie(data_key=, name_key=) | string | none / "name" | Keys for slice size and name |
pie(cx=, cy=) | number or percentage | "50%" | Center position |
pie(inner_radius=, outer_radius=) | number or percentage | 0 / "80%" | Inner and outer radius. An inner radius above 0 makes a donut |
pie(start_angle=, end_angle=) | number (degrees) | 0 / 360 | Angle range to draw. 180 and 0 make a half circle |
pie(padding_angle=, min_angle=) | number (degrees) | 0 | Gap between slices; minimum angle for small slices |
pie(fill=, stroke=) | color | accent 3 / accent 9 | Slice color and border color |
pie(label=, label_line=) | True / False / dict | False | Value labels and their connecting lines |
pie(legend_type=) | "rect" "circle" … "none" | "rect" | Legend icon |
pie(is_animation_active=, animation_begin=, animation_duration=, animation_easing=) | True / 400 / 1500 / "ease" | Entrance animation | |
cell(fill=, stroke=) | color | Color of one slice inside pie | |
| Events | on_click on_mouse_enter on_mouse_leave … | Accepted by pie_chart, pie and cell |
Two pies are drawn on top of each other around the same center. Make the inner pie small with outer_radius="50%" and hollow out the outer ring with inner_radius="60%", and you can compare two datasets in one picture. padding_angle spaces the slices apart by that many degrees.
rx.recharts.pie_chart(
rx.recharts.pie(
data=[
{"name": "Q1", "value": 400},
{"name": "Q2", "value": 300},
{"name": "Q3", "value": 300},
{"name": "Q4", "value": 200},
],
data_key="value",
name_key="name",
fill=rx.color("teal", 8),
inner_radius="60%",
padding_angle=5,
),
rx.recharts.pie(
data=[
{"name": "Q1", "value": 2400},
{"name": "Q2", "value": 4567},
{"name": "Q3", "value": 1398},
{"name": "Q4", "value": 9800},
],
data_key="value",
name_key="name",
fill=rx.color("accent", 8),
outer_radius="50%",
),
rx.recharts.graphing_tooltip(),
width="100%",
height=300,
)Without putting colors in the data, you can set them by placing one rx.recharts.cell per slice inside pie. Loop over the data with rx.foreach to build the cells and pick the index-th color from a color list. The order of the cells is the order of the slices. Set stroke to the background color with a thick border and gaps appear between the slices.
piechart_data = [
{"name": "Chrome", "value": 275},
{"name": "Safari", "value": 150},
{"name": "Firefox", "value": 100},
{"name": "Edge", "value": 130},
{"name": "Other", "value": 60},
]
rx.recharts.pie_chart(
rx.recharts.pie(
rx.foreach(
piechart_data,
lambda item, index: rx.recharts.cell(
fill=rx.Var.create(["#6366F1", "#8B5CF6", "#A855F7", "#D946EF", "#EC4899"])[index % 5],
),
),
data=piechart_data,
data_key="value",
name_key="name",
inner_radius="40%",
outer_radius="80%",
padding_angle=2,
stroke="#fff",
custom_attrs={"strokeWidth": 2},
),
rx.recharts.graphing_tooltip(),
width="100%",
height=300,
)Define radial_gradients in a zero-size rx.el.svg and point to them with url(#id) in each cell's fill. The gradient definitions can sit outside the chart as long as they are on the same page. Give each id a name that is unique on the page.
piechart_data = [
{"name": "Chrome", "value": 275},
{"name": "Safari", "value": 150},
{"name": "Firefox", "value": 100},
{"name": "Edge", "value": 130},
{"name": "Other", "value": 60},
]
rx.box(
rx.el.svg(
rx.el.svg.defs(
*[
rx.el.svg.radial_gradient(
rx.el.svg.stop(offset="10%", stop_color=color, stop_opacity=1),
rx.el.svg.stop(offset="95%", stop_color=color, stop_opacity=0.6),
id=f"piechart_grad_{i}",
cx="50%",
cy="50%",
r="50%",
)
for i, color in enumerate(["#6366F1", "#8B5CF6", "#EC4899", "#F59E0B"])
],
),
width=0,
height=0,
),
rx.recharts.pie_chart(
rx.recharts.pie(
*[rx.recharts.cell(fill=f"url(#piechart_grad_{i})") for i in range(4)],
data=piechart_data[:4],
data_key="value",
name_key="name",
inner_radius="60%",
outer_radius="80%",
padding_angle=5,
stroke="#fff",
custom_attrs={"strokeWidth": 2},
),
rx.recharts.graphing_tooltip(),
width="100%",
height=300,
),
width="100%",
)Give the pie's data a State value and the slice sizes follow whenever the numbers change. start_angle=180 and end_angle=0 make a half-circle chart, with the center moved down (cy="80%").
Wood 3
Stone 2
Gold 1
Food 4
from typing import Any
class PieChartStockState(rx.State):
stock: list[dict[str, Any]] = [
{"item": "Wood", "count": 3},
{"item": "Stone", "count": 2},
{"item": "Gold", "count": 1},
{"item": "Food", "count": 4},
]
@rx.event
def change(self, item: str, delta: int):
self.stock = [
{**row, "count": max(0, row["count"] + delta)} if row["item"] == item else row
for row in self.stock
]
rx.vstack(
rx.recharts.pie_chart(
rx.recharts.pie(
data=PieChartStockState.stock,
data_key="count",
name_key="item",
cx="50%",
cy="80%",
start_angle=180,
end_angle=0,
fill=rx.color("accent", 8),
label=True,
),
rx.recharts.graphing_tooltip(),
width="100%",
height=240,
),
rx.flex(
rx.foreach(
PieChartStockState.stock,
lambda row: rx.hstack(
rx.button("-", size="1", variant="soft", on_click=PieChartStockState.change(row["item"].to(str), -1)),
rx.text(row["item"], " ", row["count"], size="2"),
rx.button("+", size="1", variant="soft", on_click=PieChartStockState.change(row["item"].to(str), 1)),
align="center",
),
),
spacing="4",
wrap="wrap",
),
align="center",
width="100%",
)Pass the slice's index to the cell's on_mouse_enter and clear it in on_mouse_leave. The value and name of the hovered slice appear in text laid over the center of the donut. Give the text box pointer_events="none" so the mouse still reaches the slices.
Hover a slice
class PieChartHoverState(rx.State):
languages: list[dict[str, str | int]] = [
{"name": "Python", "value": 35},
{"name": "JavaScript", "value": 25},
{"name": "Java", "value": 20},
{"name": "C++", "value": 15},
{"name": "Ruby", "value": 5},
]
hovered_name: str = ""
hovered_value: int = 0
@rx.event
def enter(self, index: int):
self.hovered_name = str(self.languages[index]["name"])
self.hovered_value = int(self.languages[index]["value"])
@rx.event
def leave(self):
self.hovered_name, self.hovered_value = "", 0
rx.box(
rx.vstack(
rx.cond(
PieChartHoverState.hovered_name != "",
rx.fragment(
rx.heading(PieChartHoverState.hovered_value, "%", size="7"),
rx.text(PieChartHoverState.hovered_name, size="2"),
),
rx.text("Hover a slice", size="2", color_scheme="gray"),
),
align="center",
spacing="1",
position="absolute",
top="50%",
left="50%",
transform="translate(-50%, -50%)",
pointer_events="none",
),
rx.recharts.pie_chart(
rx.recharts.pie(
rx.foreach(
PieChartHoverState.languages,
lambda item, index: rx.recharts.cell(
fill=rx.Var.create(["#2B79D1", "#2469B3", "#1E5AA1", "#3D8EE1", "#61A9E4"])[index % 5],
on_mouse_enter=PieChartHoverState.enter(index),
on_mouse_leave=PieChartHoverState.leave,
),
),
data=PieChartHoverState.languages,
data_key="value",
name_key="name",
inner_radius=90,
stroke="0",
),
width="100%",
height=300,
),
position="relative",
width="100%",
)Five browsers are drawn as a donut, and cell paints each slice a color in a fixed order. The last one, "Other", is gray to tone it down. Values are read from the label, names from the legend and tooltip.
piechart_data = [
{"name": "Chrome", "value": 275},
{"name": "Safari", "value": 150},
{"name": "Firefox", "value": 100},
{"name": "Edge", "value": 130},
{"name": "Other", "value": 60},
]
rx.recharts.pie_chart(
rx.recharts.pie(
rx.foreach(
piechart_data,
lambda item, index: rx.recharts.cell(
fill=rx.Var.create([
rx.color("indigo", 9), rx.color("teal", 9), rx.color("orange", 9),
rx.color("plum", 9), rx.color("gray", 8),
])[index],
),
),
data=piechart_data,
data_key="value",
name_key="name",
inner_radius="55%",
outer_radius="80%",
padding_angle=2,
stroke=rx.color("gray", 1),
label=True,
),
rx.recharts.graphing_tooltip(),
rx.recharts.legend(),
width="100%",
height=320,
)Workshop notes
data goes on pie, not on pie_chart. data_key is the size, name_key is the name.
inner_radius > 0 makes a donut; start_angle and end_angle make a half circle.
Slice colors come from a "fill" key in the data, or from rx.recharts.cell placed inside pie with foreach.
Two pies overlap around the same center. Divide the space with outer_radius and inner_radius.
A cell's on_mouse_enter(index) can store the hovered slice in State.
Get news about new lessons
We'll email you when this course gets new lessons or a follow-up course opens.
R
ReflexKR
Learn Python and Reflex by doing. Every example was run and verified on Reflex 0.10.0.
ReflexKR is free, with no banner ads. If it helped you, you can support it with a coffee. ☕ Buy us a coffee
Affiliate disclosure© 2026 ReflexKR · Since 2026 · CC BY-NC 4.0
Questions & answers
Ask anything about this lesson. Questions from every language version of this page appear together.