Die Komponentenwerkstatt: Reflex' 100 Bibliotheksbausteine
·
Kursüberblick
Layout
·
Box
·
Flex
·
Stack
·
Grid
·
Container
·
Section
·
Center
·
Spacer
·
Separator
·
Card
·
Inset
·
Aspect Ratio
·
Fragment
Typografie
·
Text
·
Heading
·
Link
·
Code
·
Markdown
·
Blockquote
·
Quote
·
Strong
·
Em
·
Kbd
Formulare
·
Button
·
Input
·
Text Area
·
Checkbox
·
Switch
·
Radio Group
·
Select
·
Slider
·
Form
·
Upload
Datenanzeige
·
Badge
·
Avatar
·
Icon
·
Callout
·
List
·
Data List
·
Code Block
·
Progress
·
Spinner
·
Scroll Area
·
Moment
Auf- und Zuklappen
·
Tabs
·
Accordion
·
Segmented Control
Overlays
·
Tooltip
·
Popover
·
Hover Card
·
Dialog
·
Alert Dialog
·
Drawer
·
Dropdown Menu
·
Context Menu
·
Toast
Dynamisches Rendern
·
Cond
·
Match
·
Foreach
·
Auto Scroll
Medien
·
Image
·
Audio
·
Video
Tabellen und Datengrids
·
Table
·
Data Table
·
Data Editor
Diagramme
·
Area Chart
·
Bar Chart
·
Line Chart
·
Composed Chart
·
Pie Chart
·
Radar Chart
·
Radial Bar Chart
·
Scatter Chart
·
Funnel Chart
·
Treemap
·
Sankey Chart
·
Error Bar
Diagrammbausteine
·
Axis
·
Cartesian Grid
·
Chart Tooltip
·
Legend
·
Label
·
Reference
·
Brush
Andere Diagrammbibliotheken
·
Plotly
·
Pyplot
HTML-Elemente
·
HTML
·
HTML Text
·
HTML Layout
·
HTML Forms
·
HTML Media
·
HTML Tables
·
SVG
Weitere Werkzeuge
·
Theme
·
Skeleton
·
Clipboard
·
Html Embed
·
Script
·
Memo
Werkstattauftrag
Mach die Bestandsliste des Cafés wie in Excel direkt per Klick in die Zellen bearbeitbar, und lass bei jeder Änderung den Gesamtwert des Bestands neu berechnen.
rx.data_editor ist ein Datenraster, in dem man wie in einer Tabellenkalkulation Zellen auswählt und bearbeitet. Gezeichnet wird es mit Glide Data Grid, daher bleibt es auch bei sehr vielen Zeilen und Spalten schnell. Für reine Lesetabellen reicht Data Table; diese Komponente nimmst du, wenn Nutzer Werte ändern sollen.
columns ist eine Liste mit einem dict pro Spalte.
title: die Spaltenüberschrift.id: die id der Spalte. Fehlt sie, wird title in Kleinbuchstaben verwendet.width: die Spaltenbreite (px).type: die Art der Zelle: "str" (Standard), "int", "float", "bool" oder "image".group: zeichnet über allen Spalten mit demselben Wert eine zusätzliche Gruppenüberschrift.data ist eine Liste mit einer Liste pro Zeile. Jeder Wert muss zum type seiner Spalte passen.
rx.data_editor(
columns=[
{"title": "Code", "type": "str"},
{"title": "Value", "type": "int"},
{"title": "Activated", "type": "bool"},
],
data=[
["A", 1, True],
["B", 2, False],
["C", 3, False],
["D", 4, True],
["E", 5, True],
["F", 6, False],
],
)Klicke in das Raster und wähle Zellen, Zeilen und Spalten aus. Ein Doppelklick auf eine Zelle öffnet das Bearbeitungsfeld (dieses Labor speichert keine Werte, geänderte Werte springen also gleich wieder zurück).
Props ausprobieren
row_markers
column_select
row_select
range_select
vertical_border
show_search
rx.data_editor(
columns=[
{"title": "Code", "type": "str"},
{"title": "Value", "type": "int"},
{"title": "Activated", "type": "bool"},
],
data=[["A", 1, True], ["B", 2, False], ["C", 3, False], ["D", 4, True]],
row_markers="number",
column_select="single",
row_select="multi",
range_select="rect",
vertical_border=True,
show_search=False,
height="220px",
)| Prop | Werte | Verwendung |
|---|---|---|
columns · data | Liste | Spalteneinstellungen, Zeilendaten |
rows | Ganzzahl | Zeilenanzahl. Fehlt sie, die Länge von data |
row_height · header_height · group_header_height | Ganzzahl (px) | Höhe von Zeilen, Spaltenüberschriften und Gruppenüberschriften |
row_markers | "none" "number" "checkbox" "both" "checkbox-visible" "clickable-number" | Markierung vor jeder Zeile |
row_marker_start_index · row_marker_width | Ganzzahl | Startwert der Zeilennummern, Breite der Markierungsspalte |
freeze_columns | Ganzzahl | Anzahl der Spalten, die beim horizontalen Scrollen links fixiert bleiben |
min_column_width · max_column_width · max_column_auto_width | Ganzzahl (px) | Grenzen der Spaltenbreite |
column_select · row_select | "none" "single" "multi" | Spalten bzw. Zeilen auswählen |
range_select | "none" "cell" "rect" "multi-cell" "multi-rect" | Zellbereiche auswählen |
*_selection_blending · row_selection_mode · span_range_behavior | String | Feinheiten, etwa ob verschiedene Auswahlarten gleichzeitig bestehen dürfen |
smooth_scroll_x · smooth_scroll_y | True / False | Weiches Scrollen |
vertical_border · draw_focus_ring · fixed_shadow_x · fixed_shadow_y | True / False | Senkrechte Linien, Fokusrahmen, Schatten der fixierten Bereiche |
fill_handle | True / False | Griff an der Zellecke, mit dem man Werte durch Ziehen auffüllt |
get_cells_for_selection | True / False | Ausgewählte Zellen kopierbar machen (Standard True) |
overscroll_x · overscroll_y · scroll_offset_x · scroll_offset_y | Ganzzahl | Scrollspielraum über das Ende hinaus, anfängliche Scrollposition |
prevent_diagonal_scrolling · show_search | True / False | Diagonales Scrollen verhindern, Suchfeld |
theme | rx.data_editor_theme(...) oder dict | Farben und Schriften |
grid_selection | Auswahl-dict | Aktuelle Auswahl. Wer on_grid_selection_change nutzt, muss es unbedingt mit anbinden |
| Event | Übergebene Werte | Wann |
|---|---|---|
on_cell_clicked · on_cell_activated · on_cell_context_menu | [Spalte, Zeile] | Klick auf eine Zelle, Aktivierung per Enter oder Doppelklick, Rechtsklick |
on_cell_edited | [Spalte, Zeile], neues Zell-dict | Wenn ein Zellwert geändert wurde (der neue Wert steht in dict["data"]) |
on_finished_editing | neues Zell-dict, Bewegungsrichtung | Wenn sich das Bearbeitungsfeld schließt |
on_header_clicked · on_header_context_menu | [Spalte, Zeile] | Klick bzw. Rechtsklick auf eine Spaltenüberschrift |
on_header_menu_click | Spalte, Position | Klick auf den Menü-Button einer Spaltenüberschrift |
on_group_header_clicked · on_group_header_context_menu · on_group_header_renamed | - | Klick, Rechtsklick bzw. Umbenennen einer Gruppenüberschrift |
on_item_hovered | [Spalte, Zeile] | Wenn die Maus über eine Zelle fährt |
on_grid_selection_change · on_selection_cleared | Auswahl-dict · - | Wenn sich die Auswahl ändert bzw. aufgehoben wird |
on_delete | Auswahl-dict | Wenn in ausgewählten Zellen die Entf-Taste gedrückt wird |
on_row_appended · on_column_resize · on_search_close | - · Spalte, Breite · - | Zeile angefügt, Spaltenbreite geändert, Suchfeld geschlossen |
Eine Spalte mit type="image" zeigt Bildadressen als kleine Vorschaubilder. Der Wert kann eine einzelne Adresse sein oder eine Liste von Adressen mit mehreren Bildern. Damit die Bilder gut zu sehen sind, erhöhst du row_height. Ein Klick auf eine Bildzelle öffnet eine vergrößerte Ansicht.
rx.data_editor(
columns=[
{"title": "Preview", "type": "image", "width": 120},
{"title": "Name", "type": "str"},
],
data=[
["https://picsum.photos/id/237/160/100", "Puppy"],
["https://picsum.photos/id/1025/160/100", "Pug"],
[["https://picsum.photos/id/1084/160/100", "https://picsum.photos/id/1074/160/100"], "Two animals"],
],
row_height=90,
height="320px",
)on_cell_clicked übergibt die Position der angeklickten Zelle als [Spalte, Zeile] (beide ab 0 gezählt). Die Spalteneinstellungen unten enthalten group: "Data", daher steht über den fünf Spalten außer Title zusätzlich eine Gruppenüberschrift „Data“.
from typing import Any
class DataEditorClickState(rx.State):
clicked_data: str = "Cell clicked: "
cols: list[dict[str, Any]] = [
{"title": "Title", "type": "str"},
{"title": "Name", "type": "str", "group": "Data", "width": 220},
{"title": "Birth", "type": "str", "group": "Data", "width": 150},
{"title": "Human", "type": "bool", "group": "Data", "width": 80},
{"title": "House", "type": "str", "group": "Data"},
{"title": "Patronus", "type": "str", "group": "Data"},
]
data: list[list[Any]] = [
["1", "Harry James Potter", "31 July 1980", True, "Gryffindor", "Stag"],
["2", "Ronald Bilius Weasley", "1 March 1980", True, "Gryffindor", "Jack Russell terrier"],
["3", "Hermione Jean Granger", "19 September 1979", True, "Gryffindor", "Otter"],
["4", "Rubeus Hagrid", "6 December 1928", False, "Gryffindor", "None"],
]
@rx.event
def click_cell(self, pos: tuple[int, int]):
col, row = pos
self.clicked_data = f"Cell clicked: column {col}, row {row}"
rx.vstack(
rx.heading(DataEditorClickState.clicked_data, size="3"),
rx.data_editor(
columns=DataEditorClickState.cols,
data=DataEditorClickState.data,
on_cell_clicked=DataEditorClickState.click_cell,
height="220px",
),
width="100%",
)Der Data Editor macht Zellen nur bearbeitbar, speichert geänderte Werte aber nicht von selbst. Erst wenn der Handler für on_cell_edited Position und neue Zellinfo entgegennimmt und data im State ändert, bleibt die Änderung sichtbar. Der neue Wert steht in new_value["data"]. Ändere einen Wert per Doppelklick oder klicke auf eine Checkbox in Activated.
Die offizielle Doku zeigt für dieses Event kein Beispiel, doch für ein bearbeitbares Raster ist es unverzichtbar.
Last edit: nothing yet
from typing import Any
class DataEditorEditState(rx.State):
cols: list[dict[str, Any]] = [
{"title": "Code", "type": "str"},
{"title": "Value", "type": "int"},
{"title": "Activated", "type": "bool"},
]
data: list[list[Any]] = [["A", 1, True], ["B", 2, False], ["C", 3, False]]
last_edit: str = "nothing yet"
@rx.event
def edit_cell(self, pos: tuple[int, int], new_value: dict[str, Any]):
col, row = pos
rows = [list(r) for r in self.data]
rows[row][col] = new_value.get("data")
self.data = rows
self.last_edit = f"row {row}, column {col} -> {new_value.get('data')}"
@rx.event
def add_row(self):
self.data = self.data + [["New", 0, False]]
rx.vstack(
rx.data_editor(
columns=DataEditorEditState.cols,
data=DataEditorEditState.data,
on_cell_edited=DataEditorEditState.edit_cell,
row_markers="number",
height="200px",
),
rx.hstack(
rx.button("Add row", size="1", on_click=DataEditorEditState.add_row),
rx.text("Last edit: ", DataEditorEditState.last_edit, size="2"),
align="center",
),
width="100%",
)An theme übergibst du Farben und Schriften, entweder als Keyword-Argumente an rx.data_editor_theme(...) (in der offiziellen Doku from reflex.components.datadisplay.dataeditor import DataEditorTheme) oder direkt als dict. Die Schlüssel funktionieren sowohl mit Unterstrichen wie accent_color als auch in camelCase wie accentColor. Unten kommen zu einem dunklen Theme noch row_height=50, weiches Scrollen und die Auswahl einzelner Spalten hinzu.
dataeditor_dark_theme = {
"accent_color": "#8c96ff",
"accent_light": "rgba(202, 206, 255, 0.253)",
"text_dark": "#ffffff",
"text_medium": "#b8b8b8",
"text_light": "#a0a0a0",
"text_bubble": "#ffffff",
"bg_icon_header": "#b8b8b8",
"fg_icon_header": "#000000",
"text_header": "#a1a1a1",
"text_header_selected": "#000000",
"bg_cell": "#16161b",
"bg_cell_medium": "#202027",
"bg_header": "#212121",
"bg_header_has_focus": "#474747",
"bg_header_hovered": "#404040",
"bg_bubble": "#212121",
"bg_bubble_selected": "#000000",
"bg_search_result": "#423c24",
"border_color": "rgba(225,225,225,0.2)",
"drilldown_border": "rgba(225,225,225,0.4)",
"link_color": "#4F5DFF",
"header_font_style": "bold 14px",
"base_font_style": "13px",
}
rx.data_editor(
columns=[
{"title": "Code", "type": "str", "width": 120},
{"title": "Value", "type": "int", "width": 120},
{"title": "Activated", "type": "bool", "width": 120},
],
data=[["A", 1, True], ["B", 2, False], ["C", 3, False], ["D", 4, True], ["E", 5, True]],
row_height=50,
smooth_scroll_x=True,
smooth_scroll_y=True,
column_select="single",
theme=rx.data_editor_theme(**dataeditor_dark_theme),
height="260px",
)Die Bestandsliste wird über on_cell_edited gespeichert, Gesamtwert und Zahl der Nachbestellungen sind berechnete Variablen. Ändert man Menge oder Stückpreis, aktualisieren sich die Badges darunter sofort. Die Artikelspalte bleibt mit freeze_columns=1 fixiert.
from typing import Any
class DataEditorStockState(rx.State):
cols: list[dict[str, Any]] = [
{"title": "Item", "type": "str", "width": 160},
{"title": "Qty", "type": "int", "width": 80},
{"title": "Unit price", "type": "float", "width": 110},
{"title": "Reorder", "type": "bool", "width": 90},
]
data: list[list[Any]] = [
["Coffee beans", 12, 18.5, False],
["Paper cups", 300, 0.1, False],
["Oat milk", 4, 2.9, True],
]
@rx.event
def edit_cell(self, pos: tuple[int, int], new_value: dict[str, Any]):
col, row = pos
rows = [list(r) for r in self.data]
rows[row][col] = new_value.get("data")
self.data = rows
@rx.var
def total(self) -> str:
value = sum(float(r[1] or 0) * float(r[2] or 0) for r in self.data)
return f"${value:,.2f}"
@rx.var
def reorder_count(self) -> int:
return sum(1 for r in self.data if r[3])
rx.vstack(
rx.data_editor(
columns=DataEditorStockState.cols,
data=DataEditorStockState.data,
on_cell_edited=DataEditorStockState.edit_cell,
row_markers="number",
freeze_columns=1,
height="180px",
),
rx.hstack(
rx.badge("Stock value: ", DataEditorStockState.total, size="2"),
rx.badge("To reorder: ", DataEditorStockState.reorder_count, color_scheme="orange", size="2"),
),
width="100%",
)Werkstattnotizen
columns ist eine Liste von dicts {title, type, width, id, group}, data eine Liste von Zeilen. Die Werte passen zum type der Spalte.
type: str · int · float · bool · image.
Geänderte Werte bleiben nur, wenn on_cell_edited((Spalte, Zeile), neue Zelle) data im State ändert.
Auswahlbereiche über column_select · row_select · range_select, Zeilenmarkierung über row_markers.
theme=rx.data_editor_theme(...) oder dict; die Größe über height und row_height.
Über neue Lektionen informiert werden
Wir schicken dir eine E-Mail, wenn dieser Kurs neue Lektionen bekommt oder ein Folgekurs erscheint.
R
ReflexKR
Python und Reflex zum Anfassen. Alle Beispiele wurden mit Reflex 0.10.0 ausgeführt und geprüft.
ReflexKR ist kostenlos und ohne Werbebanner. Wenn es dir geholfen hat, kannst du es mit einem Kaffee unterstützen. ☕ Spendier uns einen Kaffee
Hinweis zu Affiliate-Links© 2026 ReflexKR · Since 2026 · CC BY-NC 4.0
Fragen & Antworten
Frag alles zu dieser Lektion. Fragen aus allen Sprachversionen dieser Seite erscheinen hier gemeinsam.