컴포넌트 공방: Reflex 라이브러리 100
·
강의 개요
레이아웃
·
Box
·
Flex
·
Stack
·
Grid
·
Container
·
Section
·
Center
·
Spacer
·
Separator
·
Card
·
Inset
·
Aspect Ratio
·
Fragment
타이포그래피
·
Text
·
Heading
·
Link
·
Code
·
Markdown
·
Blockquote
·
Quote
·
Strong
·
Em
·
Kbd
폼
·
Button
·
Input
·
Text Area
·
Checkbox
·
Switch
·
Radio Group
·
Select
·
Slider
·
Form
·
Upload
데이터 표시
·
Badge
·
Avatar
·
Icon
·
Callout
·
List
·
Data List
·
Code Block
·
Progress
·
Spinner
·
Scroll Area
·
Moment
펼침과 전환
·
Tabs
·
Accordion
·
Segmented Control
오버레이
·
Tooltip
·
Popover
·
Hover Card
·
Dialog
·
Alert Dialog
·
Drawer
·
Dropdown Menu
·
Context Menu
·
Toast
동적 렌더링
·
Cond
·
Match
·
Foreach
·
Auto Scroll
미디어
·
Image
·
Audio
·
Video
표와 데이터 그리드
·
Table
·
Data Table
·
Data Editor
차트
·
Area Chart
·
Bar Chart
·
Line Chart
·
Composed Chart
·
Pie Chart
·
Radar Chart
·
Radial Bar Chart
·
Scatter Chart
·
Funnel Chart
·
Treemap
·
Sankey Chart
·
Error Bar
차트 부품
·
Axis
·
Cartesian Grid
·
Chart Tooltip
·
Legend
·
Label
·
Reference
·
Brush
다른 차트 라이브러리
·
Plotly
·
Pyplot
HTML 요소
·
HTML
·
HTML Text
·
HTML Layout
·
HTML Forms
·
HTML Media
·
HTML Tables
·
SVG
그 밖의 도구
·
Theme
·
Skeleton
·
Clipboard
·
Html Embed
·
Script
·
Memo
공방 주문서
카페 재고표를 엑셀처럼 칸을 눌러 바로 고칠 수 있게 만들고, 고칠 때마다 재고 총액이 다시 계산되게 해 주세요.
rx.data_editor는 스프레드시트처럼 칸을 골라 고칠 수 있는 데이터 격자입니다. Glide Data Grid로 그리기 때문에 줄과 열이 아주 많아도 빠릅니다. 읽기만 하는 표는 Data Table로 충분하고, 사용자가 값을 고쳐야 할 때 이 컴포넌트를 씁니다.
columns는 열마다 dict 하나를 둔 목록입니다.
title: 열 제목입니다.id: 열의 id입니다. 없으면 title을 소문자로 바꾼 값이 됩니다.width: 열 너비(px)입니다.type: 칸의 종류입니다. "str"(기본), "int", "float", "bool", "image"를 씁니다.group: 같은 값을 가진 열들 위에 묶음 제목을 하나 더 그립니다.data는 줄마다 목록 하나를 둔 목록입니다. 각 값은 그 열의 type과 맞아야 합니다.
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],
],
)격자를 눌러 칸, 줄, 열을 골라 보세요. 칸을 두 번 누르면 고치는 창이 열립니다(이 실습대에서는 값을 저장하지 않으므로, 고친 값은 곧 원래대로 돌아갑니다).
속성 바꿔 보기
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",
)| 속성 | 값 | 쓰임 |
|---|---|---|
columns · data | 목록 | 열 설정, 줄 데이터 |
rows | 정수 | 줄 수. 없으면 data의 길이 |
row_height · header_height · group_header_height | 정수(px) | 줄, 열 제목, 묶음 제목의 높이 |
row_markers | "none" "number" "checkbox" "both" "checkbox-visible" "clickable-number" | 줄 앞 표시 |
row_marker_start_index · row_marker_width | 정수 | 줄 번호 시작값, 표시 칸 너비 |
freeze_columns | 정수 | 가로 스크롤할 때 왼쪽에 고정할 열 수 |
min_column_width · max_column_width · max_column_auto_width | 정수(px) | 열 너비의 한계 |
column_select · row_select | "none" "single" "multi" | 열·줄 고르기 |
range_select | "none" "cell" "rect" "multi-cell" "multi-rect" | 칸 범위 고르기 |
*_selection_blending · row_selection_mode · span_range_behavior | 문자열 | 여러 종류의 선택을 함께 둘지 등 세부 동작 |
smooth_scroll_x · smooth_scroll_y | True / False | 부드러운 스크롤 |
vertical_border · draw_focus_ring · fixed_shadow_x · fixed_shadow_y | True / False | 세로 선, 초점 테두리, 고정 영역 그림자 |
fill_handle | True / False | 칸 모서리를 끌어 값을 채우는 손잡이 |
get_cells_for_selection | True / False | 고른 칸을 복사할 수 있게(기본 True) |
overscroll_x · overscroll_y · scroll_offset_x · scroll_offset_y | 정수 | 끝 너머 스크롤 여유, 처음 스크롤 위치 |
prevent_diagonal_scrolling · show_search | True / False | 대각선 스크롤 막기, 검색창 |
theme | rx.data_editor_theme(...) 또는 dict | 색과 글꼴 |
grid_selection | 선택 dict | 현재 선택. on_grid_selection_change를 쓰면 꼭 함께 연결한다 |
| 이벤트 | 받는 값 | 언제 |
|---|---|---|
on_cell_clicked · on_cell_activated · on_cell_context_menu | [열, 줄] | 칸을 누를 때, Enter·두 번 누르기로 활성화할 때, 오른쪽 클릭할 때 |
on_cell_edited | [열, 줄], 새 칸 dict | 칸 값을 고쳤을 때(새 값은 dict["data"]) |
on_finished_editing | 새 칸 dict, 이동 방향 | 고치기 창이 닫힐 때 |
on_header_clicked · on_header_context_menu | [열, 줄] | 열 제목을 누를 때, 오른쪽 클릭할 때 |
on_header_menu_click | 열, 위치 | 열 제목의 메뉴 단추를 누를 때 |
on_group_header_clicked · on_group_header_context_menu · on_group_header_renamed | - | 묶음 제목을 누를 때, 오른쪽 클릭할 때, 이름을 바꿀 때 |
on_item_hovered | [열, 줄] | 마우스가 칸 위로 갈 때 |
on_grid_selection_change · on_selection_cleared | 선택 dict · - | 선택이 바뀌거나 지워질 때 |
on_delete | 선택 dict | 고른 칸에서 Delete 키를 누를 때 |
on_row_appended · on_column_resize · on_search_close | - · 열, 너비 · - | 줄 추가, 열 너비 조절, 검색창 닫기 |
type="image"인 열은 그림 주소를 작은 그림으로 보여 줍니다. 값은 주소 하나이거나, 여러 그림을 담은 주소 목록일 수 있습니다. 그림이 잘 보이도록 row_height를 늘립니다. 그림 칸을 누르면 크게 보는 창이 열립니다.
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는 누른 칸의 위치를 [열, 줄]로 넘깁니다(둘 다 0부터). 아래 열 설정에는 group: "Data"가 있어서, Title을 뺀 다섯 열 위에 "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%",
)Data Editor는 칸을 고칠 수 있게 해 줄 뿐, 고친 값을 저절로 저장하지는 않습니다. on_cell_edited 핸들러가 위치와 새 칸 정보를 받아 State의 data를 바꿔야 화면에 남습니다. 새 값은 new_value["data"]에 있습니다. 칸을 두 번 눌러 값을 고치거나, Activated 체크박스를 눌러 보세요.
공식 문서는 이 이벤트의 예제를 싣지 않았지만, 고칠 수 있는 격자를 만들려면 꼭 필요합니다.
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%",
)theme에 색과 글꼴을 넘깁니다. rx.data_editor_theme(...)(공식 문서에서는 from reflex.components.datadisplay.dataeditor import DataEditorTheme)에 키워드를 넘기거나, dict를 그대로 넘깁니다. 키는 accent_color처럼 밑줄 이름과 accentColor처럼 낙타 이름 모두 됩니다. 아래는 어두운 테마에 row_height=50, 부드러운 스크롤, 한 열씩 고르기를 더했습니다.
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",
)재고표를 on_cell_edited로 저장하고, 재고 총액과 재주문 개수를 계산 변수로 만듭니다. 수량이나 단가를 고치면 아래 배지가 바로 바뀝니다. 품목 열은 freeze_columns=1로 고정합니다.
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%",
)공방 노트
columns는 {title, type, width, id, group} dict 목록, data는 줄 목록. 값은 열의 type과 맞춘다.
type: str · int · float · bool · image.
고친 값은 on_cell_edited((열, 줄), 새 칸)에서 State의 data를 바꿔야 남는다.
고르기 범위는 column_select · row_select · range_select, 줄 앞 표시는 row_markers.
theme=rx.data_editor_theme(...) 또는 dict, 크기는 height와 row_height로 정한다.
새 교시·새 강의 소식 받기
이 강의에 새 교시가 더해지거나 이어지는 강의가 열리면 이메일로 알려 드려요.
R
ReflexKR
눌러 보며 배우는 파이썬과 Reflex. 모든 예제는 Reflex 0.10.0에서 직접 실행해 확인했습니다.
ReflexKR은 배너 광고 없이 무료로 운영돼요. 도움이 되셨다면 커피 한 잔으로 응원해 주세요.
© 2026 ReflexKR · Since 2026 · CC BY-NC 4.0
질문과 답변
이 교시에서 궁금한 점을 남겨 주세요. 모든 언어 페이지의 질문이 함께 모입니다.