컴포넌트 공방: 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.fieldsetrx.el.formrx.el.labelrx.el.legendrx.el.meterrx.el.optgrouprx.el.optionrx.el.outputrx.el.progressrx.el.selectrx.el.textarea공식 문서
공방 주문서
카페 주문 폼: 음료는 종류별로 묶인 목록에서, 받는 방법은 라디오로, 요청사항은 여러 줄로 받고, 주문하면 요약을 보여 주세요.
폼과 관련된 HTML 요소들입니다. 입력을 모으는 form, 묶음 상자 fieldset과 그 제목 legend, 고르기 select·optgroup·option, 여러 줄 입력 textarea, 값을 보여 주는 meter·progress·output이 있습니다.
Radix 폼 컴포넌트(rx.select, rx.text_area)보다 가볍고, 브라우저가 기본으로 제공하는 동작을 그대로 씁니다.
rx.el.label(
"Size ",
rx.el.select(
rx.el.option("Small", value="s"),
rx.el.option("Medium", value="m"),
rx.el.option("Large", value="l"),
default_value="m",
border="1px solid gray",
padding="2px 6px",
),
)meter는 값이 좋은 구간인지 나쁜 구간인지에 따라 색이 바뀝니다. low·high가 구간의 경계이고, optimum이 좋은 쪽을 정합니다.
속성 바꿔 보기
value
65
low
30
high
80
optimum
90
rx.el.div(
rx.el.meter(value=65, min=0, max=100, low=30, high=80, optimum=90, width="260px", height="20px"),
rx.el.progress(value=65, max=100, width="260px"),
display="flex",
flex_direction="column",
gap="10px",
)속성 바꿔 보기
placeholder
rows
resize
disabled
read_only
rx.el.textarea(
placeholder="Write a note",
rows="4",
resize="vertical",
disabled=False,
read_only=False,
border="1px solid gray",
border_radius="6px",
padding="6px 8px",
width="280px",
)| 속성 | 값 | 기본값 | 쓰임 |
|---|---|---|---|
on_submit (form) | 이벤트 핸들러 | 없음(제출을 막기만 한다) | name별 값을 담은 dict를 받는다 |
reset_on_submit (form) | True / False | False | 제출한 뒤 칸을 비운다 |
no_validate (form) | True / False | False | 브라우저의 required·pattern 검사를 끈다 |
html_for (label, output) | 요소 id | 없음 | 연결할 입력칸. 라벨을 누르면 그 칸으로 간다 |
disabled (fieldset, select, option, optgroup) | True / False | False | 안의 입력을 모두 끈다 |
value / on_change (select, textarea) | 문자열 / 이벤트 | 없음 | 제어 입력. default_value는 비제어 |
multiple size (select) | bool / 정수 | False / 없음 | 여러 개 고르기, 보이는 줄 수 |
label (optgroup) | 문자열 | 없음 | 묶음 제목 |
rows cols max_length (textarea) | 정수 | 없음 | 크기와 글자 수 제한 |
auto_height enter_key_submit (textarea) | True / False | False | 글에 맞춰 높이 늘리기, Enter로 제출 |
value min max low high optimum (meter) | 숫자 | min=0 max=1 | 범위 안의 측정값 |
value max (progress) | 숫자 | max=1 | 진행 정도. value가 없으면 진행 중 표시 |
제출 버튼을 누르면 on_submit이 폼 안 입력칸의 값을 name을 열쇠로 한 dict로 넘깁니다. 체크박스는 켜졌을 때만 "on"으로 들어갑니다.
on_submit이 없어도 rx.el.form은 브라우저의 기본 제출(페이지 새로 읽기)을 막아 둡니다. reset_on_submit=True면 제출 뒤 칸이 비워집니다.
class HtmlFormSignupState(rx.State):
submitted: dict[str, str] = {}
@rx.event
def handle_submit(self, form_data: dict):
self.submitted = {key: str(value) for key, value in form_data.items()}
rx.el.div(
rx.el.form(
rx.el.input(name="email", type="email", placeholder="Email", required=True, border="1px solid gray", padding="4px 8px"),
rx.el.select(
rx.el.option("Weekly", value="weekly"),
rx.el.option("Monthly", value="monthly"),
name="plan",
border="1px solid gray",
padding="4px",
),
rx.el.label(rx.el.input(type="checkbox", name="news"), " Send news"),
rx.el.button("Sign up", type="submit", padding="4px 12px", border="1px solid gray", border_radius="6px"),
on_submit=HtmlFormSignupState.handle_submit,
reset_on_submit=True,
display="flex",
gap="8px",
flex_wrap="wrap",
align_items="center",
),
rx.el.ul(
rx.foreach(HtmlFormSignupState.submitted, lambda kv: rx.el.li(rx.el.code(kv[0]), " = ", kv[1])),
margin_top="10px",
),
)fieldset은 관련된 입력을 테두리로 묶고, legend가 그 묶음의 제목입니다. fieldset에 disabled=True를 주면 안의 입력이 모두 꺼집니다.
label은 입력칸을 감싸거나 html_for에 입력칸의 id를 적어 연결합니다. 연결된 라벨을 누르면 입력칸으로 커서가 갑니다.
rx.el.div(
rx.el.fieldset(
rx.el.legend("Delivery", font_weight="bold"),
rx.el.label(rx.el.input(type="radio", name="ship", value="pickup", default_checked=True), " Pickup"),
rx.el.label(rx.el.input(type="radio", name="ship", value="courier"), " Courier"),
border="1px solid gray",
border_radius="6px",
padding="8px 12px",
display="flex",
gap="12px",
),
rx.el.fieldset(
rx.el.legend("Gift wrap (sold out)", font_weight="bold"),
rx.el.label(rx.el.input(type="checkbox"), " Wrap it"),
rx.el.label("Message ", rx.el.input(id="htmlforms_gift_msg", border="1px solid gray")),
disabled=True,
border="1px solid gray",
border_radius="6px",
padding="8px 12px",
display="flex",
gap="12px",
opacity="0.6",
),
rx.el.label("Coupon", html_for="htmlforms_coupon", margin_right="8px"),
rx.el.input(id="htmlforms_coupon", placeholder="Click the label", border="1px solid gray", padding="2px 6px"),
display="flex",
flex_direction="column",
gap="10px",
align_items="start",
)option이 고를 항목이고, optgroup이 항목을 label 제목 아래 묶습니다. disabled인 항목은 고를 수 없습니다.
value와 on_change로 State가 고른 값을 쥡니다. multiple=True와 size를 주면 펼쳐진 목록에서 Ctrl·Shift로 여러 개를 고릅니다.
You picked: soup
class HtmlFormSelectState(rx.State):
dish: str = "soup"
@rx.event
def change_dish(self, value: str):
self.dish = value
rx.el.div(
rx.el.select(
rx.el.optgroup(
rx.el.option("Soup", value="soup"),
rx.el.option("Salad", value="salad"),
label="Starters",
),
rx.el.optgroup(
rx.el.option("Pasta", value="pasta"),
rx.el.option("Steak (sold out)", value="steak", disabled=True),
label="Mains",
),
value=HtmlFormSelectState.dish,
on_change=HtmlFormSelectState.change_dish,
border="1px solid gray",
padding="4px",
),
rx.el.p("You picked: ", rx.el.strong(HtmlFormSelectState.dish)),
rx.el.select(
rx.el.option("Red"),
rx.el.option("Green"),
rx.el.option("Blue"),
rx.el.option("Black"),
multiple=True,
size=3,
border="1px solid gray",
width="120px",
),
display="flex",
flex_direction="column",
gap="8px",
align_items="start",
)Reflex의 rx.el.textarea에는 HTML에 없는 속성이 둘 있습니다. enter_key_submit=True면 Enter가 폼을 제출하고 Shift+Enter가 줄을 바꿉니다.
auto_height=True면 글이 길어질수록 높이가 늘어납니다(min_height와 함께 씁니다). enter_key_submit은 on_key_down과 함께 쓸 수 없습니다.
class HtmlFormChatState(rx.State):
messages: list[str] = []
@rx.event
def send(self, form_data: dict):
text = str(form_data.get("message", "")).strip()
if text:
self.messages = [*self.messages, text][-4:]
rx.el.div(
rx.el.ul(
rx.foreach(HtmlFormChatState.messages, lambda m: rx.el.li(m, white_space="pre-wrap")),
list_style_type="disc",
padding_left="1.5em",
),
rx.el.form(
rx.el.textarea(
name="message",
placeholder="Type and press Enter",
enter_key_submit=True,
auto_height=True,
max_length=200,
min_height="40px",
width="100%",
border="1px solid gray",
border_radius="6px",
padding="6px 8px",
),
on_submit=HtmlFormChatState.send,
reset_on_submit=True,
),
max_width="360px",
)output은 계산 결과를 보여 주는 자리이고, html_for에 계산에 쓰인 입력칸의 id를 공백으로 나눠 적습니다.
meter는 디스크 사용량처럼 범위가 정해진 측정값, progress는 작업의 진행 정도입니다. progress에 value를 주지 않으면 "진행 중" 표시가 됩니다.
+ =
class HtmlFormOutputState(rx.State):
a: int = 2
b: int = 3
@rx.event
def change_a(self, value: float):
self.a = int(value)
@rx.event
def change_b(self, value: float):
self.b = int(value)
@rx.var
def total(self) -> int:
return self.a + self.b
rx.el.div(
rx.el.p(
rx.el.input(id="htmlforms_a", type="number", value=HtmlFormOutputState.a, on_change=HtmlFormOutputState.change_a, width="60px", border="1px solid gray"),
" + ",
rx.el.input(id="htmlforms_b", type="number", value=HtmlFormOutputState.b, on_change=HtmlFormOutputState.change_b, width="60px", border="1px solid gray"),
" = ",
rx.el.output(HtmlFormOutputState.total, html_for="htmlforms_a htmlforms_b", name="total", font_weight="bold"),
),
rx.el.label("Disk ", rx.el.meter(value=0.7, low=0.5, high=0.8, optimum=0.2, width="160px")),
rx.el.label("Loading ", rx.el.progress(width="160px")),
display="flex",
flex_direction="column",
gap="8px",
)음료는 optgroup으로 묶고, 수량은 숫자 입력, 받는 방법은 fieldset 안의 라디오, 요청사항은 textarea입니다. 제출하면 State가 요약을 output에 씁니다.
class HtmlFormOrderState(rx.State):
summary: str = ""
@rx.event
def place_order(self, form_data: dict):
qty = form_data.get("qty") or "1"
note = str(form_data.get("note", "")).strip() or "none"
self.summary = f"{qty} x {form_data.get('drink')} ({form_data.get('size')}), {form_data.get('pickup')}. Note: {note}"
rx.el.div(
rx.el.form(
rx.el.fieldset(
rx.el.legend("Your order", font_weight="bold"),
rx.el.select(
rx.el.optgroup(rx.el.option("Latte"), rx.el.option("Mocha"), label="Coffee"),
rx.el.optgroup(rx.el.option("Green tea"), rx.el.option("Chai"), label="Tea"),
name="drink",
border="1px solid gray",
padding="4px",
),
rx.el.select(rx.el.option("Small"), rx.el.option("Large"), name="size", border="1px solid gray", padding="4px"),
rx.el.input(name="qty", type="number", min=1, max=9, default_value=1, width="60px", border="1px solid gray", padding="4px"),
display="flex",
gap="8px",
flex_wrap="wrap",
border="1px solid gray",
border_radius="6px",
padding="8px 12px",
),
rx.el.fieldset(
rx.el.legend("Pickup", font_weight="bold"),
rx.el.label(rx.el.input(type="radio", name="pickup", value="for here", default_checked=True), " For here"),
rx.el.label(rx.el.input(type="radio", name="pickup", value="to go"), " To go"),
display="flex",
gap="12px",
border="1px solid gray",
border_radius="6px",
padding="8px 12px",
),
rx.el.textarea(name="note", placeholder="Notes for the barista", rows=2, border="1px solid gray", border_radius="6px", padding="6px 8px"),
rx.el.button("Order", type="submit", padding="6px 14px", border="1px solid gray", border_radius="6px", background=rx.color("indigo", 3)),
on_submit=HtmlFormOrderState.place_order,
display="flex",
flex_direction="column",
gap="10px",
),
rx.el.output(HtmlFormOrderState.summary, display="block", margin_top="10px", font_weight="600"),
max_width="420px",
)공방 노트
rx.el.form의 on_submit은 {name: 값} dict를 받는다. 입력칸마다 name을 단다.
fieldset + legend로 묶고, fieldset의 disabled로 한꺼번에 끈다. label은 html_for로 id에 연결.
select는 option·optgroup으로, value + on_change로 제어. multiple·size로 여러 개.
textarea의 enter_key_submit·auto_height는 Reflex가 더한 편의 속성.
meter는 low·high·optimum으로 색이 바뀌는 측정값, progress는 진행, output은 계산 결과.
새 교시·새 강의 소식 받기
이 강의에 새 교시가 더해지거나 이어지는 강의가 열리면 이메일로 알려 드려요.
R
ReflexKR
눌러 보며 배우는 파이썬과 Reflex. 모든 예제는 Reflex 0.10.0에서 직접 실행해 확인했습니다.
ReflexKR은 배너 광고 없이 무료로 운영돼요. 도움이 되셨다면 커피 한 잔으로 응원해 주세요.
© 2026 ReflexKR · Since 2026 · CC BY-NC 4.0
질문과 답변
이 교시에서 궁금한 점을 남겨 주세요. 모든 언어 페이지의 질문이 함께 모입니다.