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
rx.text_areaOfficial docs
Workshop order
Add a review box to the order details screen. Up to 200 characters, with the remaining count visible, and Enter should post it right away.
rx.text_area is a multi-line text field. Use it for text that may contain line breaks: comments, support requests, notes. It works almost exactly like rx.input, plus a line count (rows), resizing (resize) and automatic height (auto_height).
rx.text_area(placeholder="Type here...")Turn on auto_height and type a few lines: the field grows with the text. resize sets the directions in which the user can resize it with the handle in the bottom-right corner.
Try the props
placeholder
rows
resize
variant
size
color
radius
auto_height
disabled
rx.text_area(placeholder="Write a comment...", rows="3", resize="vertical", variant="surface", size="2", color_scheme="indigo", radius="medium", auto_height=False, disabled=False)| Prop | Values | Default | Use |
|---|---|---|---|
placeholder | string | none | Hint shown while the field is empty |
value / default_value | string | none | Controlled value / value set only once at the start |
rows, cols | number as string | browser value | Lines shown at first, width in characters |
resize | "none" "vertical" "horizontal" "both" | theme value | Directions in which the user can resize |
auto_height | True / False | False | Grows with the text (together with min_height) |
enter_key_submit | True / False / Var | False | Enter submits the form, Shift+Enter adds a line break |
variant, size, color_scheme, radius | same as Input | Look | |
name, required, max_length, min_length | none | Form field name and browser checks | |
disabled, read_only, auto_focus | True / False | False | Disable, read-only, autofocus |
on_change, on_blur | event | When the value changes / focus is lost. Passes the value | |
on_key_down, on_key_up | event | When a key is pressed / released |
As with Input, on_blur passes the text written so far once, when you leave the field. Give it value and on_change together and it becomes a controlled input, again with debouncing added automatically.
class TextAreaBlurState(rx.State):
text: str = "Hello World!"
@rx.event
def set_text(self, text: str):
self.text = text
rx.vstack(
rx.heading(TextAreaBlurState.text, size="4"),
rx.text_area(placeholder="Type, then click outside", on_blur=TextAreaBlurState.set_text),
width="100%",
)In form data, name becomes the key. Below is the feedback form from the official docs. The State holds the field through value + on_change, and after sending, rx.cond swaps it for a thank-you card. Because of required=True, an empty message can't be sent.
class TextAreaFeedbackState(rx.State):
feedback: str = ""
submitted: bool = False
@rx.event
def set_feedback(self, value: str):
self.feedback = value
@rx.event
def submit_feedback(self, form_data: dict):
self.submitted = True
@rx.event
def reset_form(self):
self.feedback = ""
self.submitted = False
rx.cond(
TextAreaFeedbackState.submitted,
rx.card(
rx.vstack(
rx.text("Thank you! You wrote:"),
rx.blockquote(TextAreaFeedbackState.feedback),
rx.button("Submit another response", on_click=TextAreaFeedbackState.reset_form),
),
),
rx.card(
rx.form(
rx.flex(
rx.text("Are you enjoying Reflex?"),
rx.text_area(
name="feedback",
placeholder="Write your feedback...",
value=TextAreaFeedbackState.feedback,
on_change=TextAreaFeedbackState.set_feedback,
resize="vertical",
required=True,
),
rx.button("Send", type="submit"),
direction="column",
spacing="3",
),
on_submit=TextAreaFeedbackState.submit_feedback,
),
),
)In a multi-line field, Enter normally inserts a line break. With enter_key_submit=True, Enter submits the surrounding form and Shift+Enter becomes the line break. The prop also accepts a Var, so you can toggle it with a switch as below. To turn it off while something is processing, write enter_key_submit=~State.is_loading.
enter_key_submit uses its own key handler, so it can't be combined with on_key_down (doing so raises a ValueError). A Python on_key_down handler only receives the key name, so it can't prevent the line break either. If you need both, you need browser-side handling such as rx.call_script.
Enter submits
Nothing submitted yet.
class TextAreaEnterState(rx.State):
submitted_text: str = ""
enter_submits: bool = True
@rx.event
def handle_submit(self, form_data: dict):
self.submitted_text = form_data.get("message", "")
@rx.event
def set_enter_submits(self, value: bool):
self.enter_submits = value
rx.vstack(
rx.hstack(
rx.switch(checked=TextAreaEnterState.enter_submits, on_change=TextAreaEnterState.set_enter_submits),
rx.text("Enter submits", size="2"),
align="center",
),
rx.form(
rx.text_area(
name="message",
placeholder="Type and press Enter (Shift+Enter for a new line)",
enter_key_submit=TextAreaEnterState.enter_submits,
),
on_submit=TextAreaEnterState.handle_submit,
reset_on_submit=True,
width="100%",
),
rx.cond(
TextAreaEnterState.submitted_text != "",
rx.text("Submitted: ", rx.code(TextAreaEnterState.submitted_text)),
rx.text("Nothing submitted yet.", color_scheme="gray"),
),
width="100%",
)With auto_height=True, the field grows with the text instead of scrolling inside. Add rows="1" and min_height="0" and it starts at one line and grows from there. To stop it growing too much, give it a max_height. The one below stops at 160px.
rx.text_area(
placeholder="Type a few lines - the box grows to fit",
auto_height=True,
rows="1",
min_height="0",
max_height="160px",
width="100%",
)The State holds the text through value + on_change, and the computed var left shows how many characters remain. The browser limits the length with max_length, and the server limits it again with [:200]. On save, it uses the value from form_data, so no characters still held back by the debounce are lost. auto_height lets it grow, and enter_key_submit posts it when you press Enter.
class TextAreaReviewState(rx.State):
review: str = ""
saved: str = ""
@rx.event
def set_review(self, value: str):
self.review = value[:200]
@rx.event
def save(self, form_data: dict):
self.saved = form_data.get("review", "")[:200]
self.review = ""
@rx.var
def left(self) -> int:
return 200 - len(self.review)
rx.form(
rx.vstack(
rx.text_area(
name="review",
placeholder="How was your order?",
value=TextAreaReviewState.review,
on_change=TextAreaReviewState.set_review,
max_length=200,
auto_height=True,
rows="2",
min_height="0",
enter_key_submit=True,
width="100%",
),
rx.hstack(
rx.text(TextAreaReviewState.left, " characters left", size="1", color_scheme="gray"),
rx.spacer(),
rx.button("Post review", type="submit", disabled=TextAreaReviewState.review == ""),
width="100%",
align="center",
),
rx.cond(TextAreaReviewState.saved != "", rx.callout(TextAreaReviewState.saved, icon="message-square")),
width="100%",
),
on_submit=TextAreaReviewState.save,
width="100%",
max_width="460px",
)Workshop notes
rx.text_area is multi-line input. It works like rx.input (on_blur, value + on_change).
rows sets the initial line count; resize sets the directions the user can stretch it.
auto_height=True + rows="1" + min_height="0" makes it grow with the text. Cap it with max_height.
enter_key_submit=True makes Enter submit the form and Shift+Enter add a line break. It can't be combined with on_key_down.
In a form, name is the key, and the browser checks required and max_length.
Get news about new lessons
We'll email you when this course gets new lessons or a follow-up course opens.
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© 2026 ReflexKR · Since 2026 · CC BY-NC 4.0
Questions & answers
Ask anything about this lesson. Questions from every language version of this page appear together.