R

ReflexKR

Reflex Docs

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

The Component Workshop: Reflex's 100 Library Components
Charts

Bar Chart

rx.recharts.bar_chartrx.recharts.barrx.recharts.cell

Official docs

Workshop order

Please put coffee and tea sales side by side for each store, so we can compare which store sells more of what.

rx.recharts.bar_chart raises one bar per item so you can compare sizes. It is the first chart to reach for when comparing separate items, such as sales per store or counts per category. Give the chart container data, then add one rx.recharts.bar(data_key=…) for each series you want to draw.

Most examples on this page use the barchart_data below.

barchart_data = [
    {"store": "North", "coffee": 4000, "tea": 2400},
    {"store": "South", "coffee": 3000, "tea": 1398},
    {"store": "East", "coffee": 2000, "tea": 5800},
    {"store": "West", "coffee": 2780, "tea": 3908},
    {"store": "Center", "coffee": 1890, "tea": 4800},
]


rx.recharts.bar_chart(
    rx.recharts.bar(data_key="coffee", fill=rx.color("accent", 8)),
    rx.recharts.x_axis(data_key="store"),
    rx.recharts.y_axis(),
    data=barchart_data,
    width="100%",
    height=250,
)

Try the props

With two bars, the bars for each item stand side by side. Change the gap between items (bar_category_gap), the gap between bars within an item (bar_gap) and the gray backdrop behind the bars (background).

Try the props

color

bar_category_gap

bar_gap

background

rx.recharts.bar_chart(
    rx.recharts.bar(
        data_key="coffee",
        fill=rx.color("indigo", 8),
        background=False,
    ),
    rx.recharts.bar(
        data_key="tea",
        fill=rx.color("teal", 8),
        background=False,
    ),
    rx.recharts.x_axis(data_key="store"),
    rx.recharts.y_axis(),
    data=barchart_data,
    bar_category_gap="10%",
    bar_gap="5%",
    width="100%",
    height=250,
)
Gaps take a percentage string or a pixel number. Turn on background and the whole slot each bar could fill is lightly shaded.
PropValuesDefaultUse
bar_chart(data=)list of dictsnoneData used by the whole chart
bar_chart(layout=)"horizontal" "vertical""horizontal"Vertical bars or horizontal bars
bar_chart(bar_category_gap=)percentage or number"10%"Gap between items
bar_chart(bar_gap=)percentage or number4Gap between bars within one item
bar_chart(bar_size=, max_bar_size=)numberautoThickness of every bar; maximum thickness
bar_chart(stack_offset=)"none" "expand" "wiggle" "silhouette""none"How the baseline of stacked bars is computed
bar_chart(reverse_stack_order=)True / FalseFalseReverses the stacking order
bar_chart(sync_id=, margin=)string / dictnoneLink with other charts; space around the chart
bar(data_key=)stringnoneKey of the value to draw. A [low, high] value makes a range bar
bar(fill=, stroke=)coloraccent 9 / noneBar color and border color
bar(stack_id=)stringnoneBars with the same value stack on top of each other
bar(radius=)number or [top-left, top-right, bottom-right, bottom-left]0Corner rounding
bar(background=)True / FalseFalseBackdrop for the bar's slot
bar(min_point_size=)numbernoneKeeps values near 0 visible at least this tall
bar(name=, unit=, label=)string / boolTooltip and legend name, unit, number on top of the bar
on_click on_mouse_enter …eventsAccepted by the chart, bar and cell

Stacked bars and 100% bars

bars with the same stack_id pile up one after another in a single bar, and the total height of the bar is the sum. Give the chart stack_offset="expand" and every bar becomes the same height, leaving only the proportions of each part.

barchart_data = [
    {"store": "North", "coffee": 4000, "tea": 2400},
    {"store": "South", "coffee": 3000, "tea": 1398},
    {"store": "East", "coffee": 2000, "tea": 5800},
    {"store": "West", "coffee": 2780, "tea": 3908},
    {"store": "Center", "coffee": 1890, "tea": 4800},
]


rx.flex(
    rx.recharts.bar_chart(
        rx.recharts.bar(data_key="coffee", stack_id="1", fill=rx.color("accent", 8)),
        rx.recharts.bar(data_key="tea", stack_id="1", fill=rx.color("teal", 8)),
        rx.recharts.x_axis(data_key="store"),
        rx.recharts.y_axis(),
        rx.recharts.legend(),
        data=barchart_data,
        width="100%",
        height=250,
    ),
    rx.recharts.bar_chart(
        rx.recharts.bar(data_key="coffee", stack_id="1", fill=rx.color("accent", 8)),
        rx.recharts.bar(data_key="tea", stack_id="1", fill=rx.color("teal", 8)),
        rx.recharts.x_axis(data_key="store"),
        rx.recharts.y_axis(),
        rx.recharts.legend(),
        data=barchart_data,
        stack_offset="expand",
        width="100%",
        height=250,
    ),
    direction="column",
    spacing="4",
    width="100%",
)

Range bars

If the value data_key points to is not a single number but a pair [low, high], the bar starts at the low value instead of 0 and ends at the high one. Use this to show ranges, such as a day's lowest and highest temperatures.

rx.recharts.bar_chart(
    rx.recharts.bar(
        data_key="temperature",
        stroke=rx.color("accent", 9),
        fill=rx.color("accent", 7),
    ),
    rx.recharts.x_axis(data_key="day"),
    rx.recharts.y_axis(),
    rx.recharts.graphing_tooltip(),
    data=[
        {"day": "Mon", "temperature": [-1, 10]},
        {"day": "Tue", "temperature": [2, 15]},
        {"day": "Wed", "temperature": [3, 12]},
        {"day": "Thu", "temperature": [4, 12]},
        {"day": "Fri", "temperature": [12, 16]},
        {"day": "Sat", "temperature": [5, 16]},
        {"day": "Sun", "temperature": [0, 8]},
    ],
    width="100%",
    height=250,
)

Bar thickness and gaps

bar_size sets the thickness of every bar in pixels, and max_bar_size caps it. The example below has bar_size=100, but max_bar_size=24 wins, so no bar is wider than 24 pixels. This is handy for keeping bars from getting too fat when there are only a few items.

barchart_data = [
    {"store": "North", "coffee": 4000, "tea": 2400},
    {"store": "South", "coffee": 3000, "tea": 1398},
    {"store": "East", "coffee": 2000, "tea": 5800},
    {"store": "West", "coffee": 2780, "tea": 3908},
    {"store": "Center", "coffee": 1890, "tea": 4800},
]


rx.recharts.bar_chart(
    rx.recharts.bar(data_key="coffee", fill=rx.color("accent", 8)),
    rx.recharts.bar(data_key="tea", fill=rx.color("teal", 8)),
    rx.recharts.x_axis(data_key="store"),
    rx.recharts.y_axis(),
    data=barchart_data,
    bar_category_gap="15%",
    bar_gap=6,
    bar_size=100,
    max_bar_size=24,
    width="100%",
    height=250,
)

Rounded corners and gradients

A single number for radius rounds all four corners; a list like [8, 8, 0, 0] sets them separately in the order top-left, top-right, bottom-right, bottom-left. Rounding only the top makes the bars look as if they stand on the floor. As with area charts, the fill can be a gradient from rx.el.svg.defs referenced with url(#id).

barchart_data = [
    {"store": "North", "coffee": 4000, "tea": 2400},
    {"store": "South", "coffee": 3000, "tea": 1398},
    {"store": "East", "coffee": 2000, "tea": 5800},
    {"store": "West", "coffee": 2780, "tea": 3908},
    {"store": "Center", "coffee": 1890, "tea": 4800},
]


rx.recharts.bar_chart(
    rx.el.svg.defs(
        rx.el.svg.linear_gradient(
            rx.el.svg.stop(offset="5%", stop_color=rx.color("accent", 9), stop_opacity=0.9),
            rx.el.svg.stop(offset="95%", stop_color=rx.color("accent", 9), stop_opacity=0.2),
            id="barchart_gradient",
            x1=0,
            y1=0,
            x2=0,
            y2=1,
        ),
    ),
    rx.recharts.bar(
        data_key="coffee",
        fill=rx.color("teal", 8),
        radius=8,
    ),
    rx.recharts.bar(
        data_key="tea",
        fill="url(#barchart_gradient)",
        radius=[8, 8, 0, 0],
    ),
    rx.recharts.x_axis(data_key="store"),
    rx.recharts.y_axis(),
    rx.recharts.graphing_tooltip(),
    data=barchart_data,
    width="100%",
    height=250,
)

Horizontal bars (layout)

layout="vertical" turns it into a horizontal bar chart, with bars reaching from left to right. Switch the x-axis to numbers (type_="number") and the y-axis to categories (type_="category"). This reads better when item names are long.

barchart_data = [
    {"store": "North", "coffee": 4000, "tea": 2400},
    {"store": "South", "coffee": 3000, "tea": 1398},
    {"store": "East", "coffee": 2000, "tea": 5800},
    {"store": "West", "coffee": 2780, "tea": 3908},
    {"store": "Center", "coffee": 1890, "tea": 4800},
]


rx.recharts.bar_chart(
    rx.recharts.bar(
        data_key="coffee",
        stroke=rx.color("accent", 8),
        fill=rx.color("accent", 4),
    ),
    rx.recharts.x_axis(type_="number"),
    rx.recharts.y_axis(data_key="store", type_="category"),
    data=barchart_data,
    layout="vertical",
    margin={"top": 20, "right": 20, "left": 20, "bottom": 20},
    width="100%",
    height=280,
)

State and clicks

Connect data to a State value and the bars grow with an animation whenever it changes. Click anywhere on the chart below (the on_click of bar_chart) and new numbers are drawn.

import random
from typing import Any


class BarChartLiveState(rx.State):
    data: list[dict[str, Any]] = [
        {"store": "North", "coffee": 4000, "tea": 2400},
        {"store": "South", "coffee": 3000, "tea": 1398},
        {"store": "East", "coffee": 2000, "tea": 5800},
        {"store": "West", "coffee": 2780, "tea": 3908},
    ]

    @rx.event
    def shuffle(self):
        self.data = [
            {**row, "coffee": random.randint(500, 6000), "tea": random.randint(500, 6000)}
            for row in self.data
        ]


rx.recharts.bar_chart(
    rx.recharts.cartesian_grid(stroke_dasharray="3 3"),
    rx.recharts.bar(data_key="coffee", fill=rx.color("accent", 8)),
    rx.recharts.bar(data_key="tea", fill=rx.color("teal", 8)),
    rx.recharts.x_axis(data_key="store"),
    rx.recharts.y_axis(),
    rx.recharts.legend(),
    on_click=BarChartLiveState.shuffle,
    data=BarChartLiveState.data,
    width="100%",
    height=280,
)

To give each bar its own behavior, use rx.recharts.cell. Build one cell per data row with rx.foreach inside the bar, and each cell takes charge of the bar at the same position. Passing the item's name to that cell's on_click makes a drill-down that keeps only the clicked bar. Click the same bar again to return to the full view.

  • The foreach function receives (item, index) and returns one cell.
  • The click handler is bound to that item's value when the UI is built (toggle(item["name"].to(str))).
  • rx.cond paints only the selected bar a different color.
  • The chart's data is itself a computed var (rows), so picking a bar redraws the chart with just that item.

The same technique works for pie charts (put the cells inside pie).

barchart_genres = [
    {"name": "Fiction", "count": 42},
    {"name": "History", "count": 28},
    {"name": "Science", "count": 35},
    {"name": "Biography", "count": 17},
    {"name": "Fantasy", "count": 24},
]

barchart_colors = ["#6366F1", "#8B5CF6", "#A855F7", "#D946EF", "#EC4899"]


class BarChartDrillState(rx.State):
    picked: str = ""

    @rx.var
    def rows(self) -> list[dict[str, str | int]]:
        if self.picked:
            return [g for g in barchart_genres if g["name"] == self.picked]
        return barchart_genres

    @rx.event
    def toggle(self, name: str):
        self.picked = "" if self.picked == name else name


rx.recharts.bar_chart(
    rx.recharts.cartesian_grid(stroke_dasharray="3 3", vertical=False),
    rx.recharts.x_axis(data_key="name", tick_line=False, axis_line=False),
    rx.recharts.y_axis(allow_decimals=False, axis_line=False, tick_line=False),
    rx.recharts.bar(
        rx.foreach(
            BarChartDrillState.rows,
            lambda item, index: rx.recharts.cell(
                on_click=BarChartDrillState.toggle(item["name"].to(str)),
                custom_attrs={"cursor": "pointer"},
                fill=rx.cond(
                    BarChartDrillState.picked == item["name"],
                    "#1D4ED8",
                    rx.Var.create(barchart_colors)[index % 5],
                ),
            ),
        ),
        data_key="count",
        radius=[4, 4, 0, 0],
    ),
    rx.recharts.graphing_tooltip(),
    data=BarChartDrillState.rows,
    width="100%",
    height=280,
)

Filling the order

Coffee and tea bars stand side by side for each store, with only the top corners rounded. max_bar_size keeps the bars from getting too thick, and the tooltip and legend let people read the values and names.

barchart_data = [
    {"store": "North", "coffee": 4000, "tea": 2400},
    {"store": "South", "coffee": 3000, "tea": 1398},
    {"store": "East", "coffee": 2000, "tea": 5800},
    {"store": "West", "coffee": 2780, "tea": 3908},
    {"store": "Center", "coffee": 1890, "tea": 4800},
]


rx.recharts.bar_chart(
    rx.recharts.cartesian_grid(stroke_dasharray="3 3", vertical=False),
    rx.recharts.bar(data_key="coffee", name="Coffee", fill=rx.color("accent", 8), radius=[4, 4, 0, 0]),
    rx.recharts.bar(data_key="tea", name="Tea", fill=rx.color("teal", 8), radius=[4, 4, 0, 0]),
    rx.recharts.x_axis(data_key="store"),
    rx.recharts.y_axis(),
    rx.recharts.graphing_tooltip(),
    rx.recharts.legend(),
    data=barchart_data,
    bar_gap=2,
    max_bar_size=32,
    width="100%",
    height=300,
)

Workshop notes

  • Inside bar_chart(data=…), one bar(data_key=…) per series puts them side by side; a shared stack_id stacks them.

  • stack_offset="expand" gives 100% bars; a [low, high] value for data_key gives range bars.

  • Gaps are bar_category_gap and bar_gap, thickness is bar_size and max_bar_size, corners are radius.

  • layout="vertical" makes horizontal bars. Change the axes' type_ along with it.

  • For a different color or click per bar, put rx.recharts.cell inside bar with foreach.

← Previous

Charts · Area Chart

Next →

Charts · Line Chart

Get news about new lessons

We'll email you when this course gets new lessons or a follow-up course opens.

We collect: your email address · Purpose: news about new lessons or the launch of this course · Kept until: you ask us to remove it. We never use it for anything else or share it. Reply to any notice email and we'll delete it right away.

Questions & answers

Ask anything about this lesson. Questions from every language version of this page appear together.

Shown as plain text, without links or formatting.

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
한국어English日本語简体中文EspañolDeutsch

© 2026 ReflexKR · Since 2026 · CC BY-NC 4.0

Built with Reflex