컴포넌트 공방: 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.el.tablerx.el.captionrx.el.colgrouprx.el.colrx.el.theadrx.el.tbodyrx.el.tfootrx.el.trrx.el.thrx.el.td공식 문서
공방 주문서
카페 영수증을 표로: 제목, 품목·수량·가격 머리줄, 합계가 들어간 바닥줄까지 맨 HTML 표로 짜 주세요.
행과 열로 된 자료를 보여 주는 HTML 표 요소들입니다. table 안의 tbody에 줄 tr을 두고, 줄 안에 머리칸 th와 보통 칸 td를 둡니다.
스타일이 없으므로 테두리와 여백을 직접 줍니다. Radix 모양의 표가 필요하면 rx.table, 정렬·검색이 있는 표는 rx.data_table을 씁니다.
| Name | Role |
|---|---|
| Ada | Engineer |
| Linus | Maintainer |
rx.el.table(
rx.el.tbody(
rx.el.tr(rx.el.th("Name"), rx.el.th("Role")),
rx.el.tr(rx.el.td("Ada"), rx.el.td("Engineer")),
rx.el.tr(rx.el.td("Linus"), rx.el.td("Maintainer")),
),
)이 사이트의 preflight는 표의 칸 사이를 붙여 둡니다(border_collapse="collapse"). separate로 바꾸면 칸마다 테두리가 떨어집니다.
속성 바꿔 보기
| Item | Qty |
|---|---|
| Apples | 3 |
| Pears | 12 |
caption
caption_side
align
collapse
rx.el.table(
rx.el.caption("Fruit stock", caption_side="top", padding="4px", font_weight="600"),
rx.el.thead(
rx.el.tr(
rx.el.th("Item", border="1px solid gray", padding="6px"),
rx.el.th("Qty", border="1px solid gray", padding="6px"),
),
),
rx.el.tbody(
rx.el.tr(
rx.el.td("Apples", border="1px solid gray", padding="6px"),
rx.el.td("3", align="right", border="1px solid gray", padding="6px"),
),
rx.el.tr(
rx.el.td("Pears", border="1px solid gray", padding="6px"),
rx.el.td("12", align="right", border="1px solid gray", padding="6px"),
),
),
border_collapse="collapse",
border_spacing="4px",
width="260px",
)| 속성 | 값 | 기본값 | 쓰임 |
|---|---|---|---|
col_span (td, th) | 정수 | 1 | 가로로 합칠 칸 수 |
row_span (td, th) | 정수 | 1 | 세로로 합칠 칸 수 |
scope (th) | "col" "row" "colgroup" "rowgroup" | 없음 | 이 머리칸이 맡는 방향 |
headers (td, th) | th의 id들 | 없음 | 이 칸의 머리칸을 직접 지정 |
align (td, th) | "left" "center" "right" "justify" "char" | 왼쪽 | 칸 안 정렬(옛 속성, CSS text_align도 된다) |
span (col, colgroup) | 정수 | 1 | 한 col이 맡는 열 수 |
align summary (table) | 문자열 | 없음 | HTML5에서 폐기된 옛 속성. 정렬은 CSS, 설명은 caption으로 |
thead·tbody·tfoot은 줄을 머리·몸통·바닥으로 나눕니다. 줄은 꼭 이 셋 중 하나에 넣습니다.
table 바로 아래에 tr을 두면 브라우저가 몰래 tbody를 끼워 넣어, React가 아는 구조와 어긋날 수 있습니다.
caption은 표의 제목으로 table의 첫 자식이어야 합니다. th의 scope는 그 머리칸이 열("col")을 맡는지 줄("row")을 맡는지 알려 줍니다.
| Month | Visitors |
|---|---|
| Jan | 1,200 |
| Feb | 1,450 |
| Total | 2,650 |
rx.el.table(
rx.el.caption("Monthly visitors", padding="4px", font_weight="600"),
rx.el.thead(
rx.el.tr(rx.el.th("Month", scope="col"), rx.el.th("Visitors", scope="col")),
background=rx.color("indigo", 3),
),
rx.el.tbody(
rx.el.tr(rx.el.th("Jan", scope="row"), rx.el.td("1,200")),
rx.el.tr(rx.el.th("Feb", scope="row"), rx.el.td("1,450")),
),
rx.el.tfoot(
rx.el.tr(rx.el.th("Total", scope="row"), rx.el.td("2,650", font_weight="bold")),
border_top="2px solid gray",
),
width="280px",
text_align="left",
)col_span=2는 오른쪽 칸 하나를 먹고, row_span=2는 아래 줄의 칸 하나를 먹습니다. 먹힌 자리에는 td를 두지 않습니다.
아래 시간표에서 셋째 줄은 칸이 하나 적습니다.
| Mon | Tue | Wed | |
|---|---|---|---|
| 9 am | Workshop | Free | |
| 10 am | Lunch prep | Review | Free |
| 11 am | Free | Demo | |
rx.el.table(
rx.el.thead(rx.el.tr(rx.el.th(""), rx.el.th("Mon"), rx.el.th("Tue"), rx.el.th("Wed"))),
rx.el.tbody(
rx.el.tr(rx.el.th("9 am"), rx.el.td("Workshop", col_span=2, background=rx.color("indigo", 4)), rx.el.td("Free")),
rx.el.tr(rx.el.th("10 am"), rx.el.td("Lunch prep", row_span=2, background=rx.color("amber", 4)), rx.el.td("Review"), rx.el.td("Free")),
rx.el.tr(rx.el.th("11 am"), rx.el.td("Free"), rx.el.td("Demo")),
),
border="1px solid gray",
text_align="center",
width="340px",
)colgroup 안의 col 하나가 한 열을 맡고, span=2면 두 열을 맡습니다. 열 전체에 배경색·폭을 줄 때 씁니다.
col에 쓸 수 있는 CSS는 background, width, border, visibility 정도로 한정됩니다.
| Plan | Price | Seats |
|---|---|---|
| Starter | $0 | 1 |
| Team | $20 | 10 |
rx.el.table(
rx.el.colgroup(rx.el.col(), rx.el.col(span=2)),
rx.el.thead(rx.el.tr(rx.el.th("Plan"), rx.el.th("Price"), rx.el.th("Seats"))),
rx.el.tbody(
rx.el.tr(rx.el.td("Starter"), rx.el.td("$0"), rx.el.td("1")),
rx.el.tr(rx.el.td("Team"), rx.el.td("$20"), rx.el.td("10")),
),
width="300px",
text_align="left",
# style the columns from the table: Reflex puts a <style> tag next to a styled
# element, and the browser moves a <style> found inside <colgroup> out of it
style={
"& col:first-child": {"background": rx.color("gray", 3)},
"& col:last-child": {"background": rx.color("teal", 3)},
},
)복잡한 표에서는 th에 id를 달고, td의 headers에 그 id를 적어 연결합니다. 화면은 같지만 화면 읽기 프로그램이 "Price, $2"처럼 읽습니다.
| Fruit | Price |
|---|---|
| Kiwi | $2 |
rx.el.table(
rx.el.tbody(
rx.el.tr(rx.el.th("Fruit", id="htmltable_fruit"), rx.el.th("Price", id="htmltable_price")),
rx.el.tr(rx.el.td("Kiwi", headers="htmltable_fruit"), rx.el.td("$2", headers="htmltable_price")),
),
width="200px",
text_align="left",
)줄이 State의 목록에서 나오면 rx.foreach로 tr을 만듭니다. 정렬은 계산 변수에서 하고, 표는 그 결과를 그대로 그립니다.
| Name | Score |
|---|---|
| Jun | 95 |
| Mina | 88 |
| Sora | 72 |
class HtmlTableScoreState(rx.State):
rows: list[dict[str, str]] = [
{"name": "Mina", "score": "88"},
{"name": "Jun", "score": "95"},
{"name": "Sora", "score": "72"},
]
descending: bool = True
@rx.event
def flip_order(self):
self.descending = not self.descending
@rx.var
def sorted_rows(self) -> list[dict[str, str]]:
return sorted(self.rows, key=lambda r: int(r["score"]), reverse=self.descending)
rx.el.div(
rx.el.button(
rx.cond(HtmlTableScoreState.descending, "High to low", "Low to high"),
on_click=HtmlTableScoreState.flip_order,
padding="4px 12px",
border="1px solid gray",
border_radius="6px",
margin_bottom="8px",
),
rx.el.table(
rx.el.thead(rx.el.tr(rx.el.th("Name"), rx.el.th("Score"))),
rx.el.tbody(
rx.foreach(
HtmlTableScoreState.sorted_rows,
lambda row: rx.el.tr(rx.el.td(row["name"]), rx.el.td(row["score"], align="right")),
),
),
width="220px",
text_align="left",
),
)caption이 영수증 번호, thead가 머리줄, tfoot이 합계입니다. 합계 머리칸은 col_span=2로 두 열을 차지하고, 숫자 열은 colgroup으로 폭을 맞췄습니다.
| Item | Qty | Price |
|---|---|---|
| Latte | 2 | $9.00 |
| Bagel | 1 | $3.50 |
| Total | $12.50 | |
rx.el.table(
rx.el.caption("Receipt #1024", padding="6px", font_weight="bold"),
rx.el.colgroup(rx.el.col(), rx.el.col(span=2)),
rx.el.thead(
rx.el.tr(rx.el.th("Item", scope="col"), rx.el.th("Qty", scope="col"), rx.el.th("Price", scope="col")),
border_bottom="2px solid gray",
),
rx.el.tbody(
rx.el.tr(rx.el.td("Latte"), rx.el.td("2", align="right"), rx.el.td("$9.00", align="right")),
rx.el.tr(rx.el.td("Bagel"), rx.el.td("1", align="right"), rx.el.td("$3.50", align="right")),
),
rx.el.tfoot(
rx.el.tr(rx.el.th("Total", scope="row", col_span=2), rx.el.td("$12.50", align="right", font_weight="bold")),
border_top="2px solid gray",
),
width="300px",
text_align="left",
font_variant_numeric="tabular-nums",
style={"& col:last-child": {"width": "70px"}}, # see the colgroup example above
)공방 노트
table > (caption) > thead · tbody · tfoot > tr > th · td. tr은 꼭 tbody 등에 넣는다.
preflight 아래의 표는 테두리도 여백도 없다. border·padding을 직접.
col_span·row_span으로 칸을 합치고, 먹힌 자리에는 칸을 두지 않는다.
th의 scope, td의 headers는 화면 읽기 프로그램을 위한 연결.
줄이 State에서 오면 rx.foreach로 tr을 만든다. 꾸민 표가 필요하면 rx.table.
새 교시·새 강의 소식 받기
이 강의에 새 교시가 더해지거나 이어지는 강의가 열리면 이메일로 알려 드려요.
R
ReflexKR
눌러 보며 배우는 파이썬과 Reflex. 모든 예제는 Reflex 0.10.0에서 직접 실행해 확인했습니다.
ReflexKR은 배너 광고 없이 무료로 운영돼요. 도움이 되셨다면 커피 한 잔으로 응원해 주세요.
© 2026 ReflexKR · Since 2026 · CC BY-NC 4.0
질문과 답변
이 교시에서 궁금한 점을 남겨 주세요. 모든 언어 페이지의 질문이 함께 모입니다.