Text Area
A multi-line text input.
use herogpui::components::textarea::TextArea;TextArea on docs.rsSource at v0.14.0
Usage
Showing Usage, live: HeroGPUI compiled to WebAssembly. The canvas has no accessibility tree; each example's description and code below carry the same information.
Platform edits support composed text and paste. Enter confirms active composition before inserting a newline. Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.
use herogpui::prelude::TextArea;
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;
gpui::div()
.flex()
.flex_col()
.items_start()
.justify_center()
.gap(px(12.))
.children(vec![gpui::div()
.w(px(384.))
.child(TextArea::new(self.demo_text("ta-usage", "", cx))
.placeholder("Share a quick project update...")
.cols(48)
.rows(6)
.full_width())
.into_any_element()])Labels use 14px text with 20px lines; helper and error text use 12px text with 16px lines. Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.
use herogpui::prelude::{FieldVariant, TextArea};
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;
gpui::div()
.flex()
.flex_col()
.w(px(256.))
.gap(px(12.))
.children(vec![
TextArea::new(self.demo_text("ta-primary", "", cx))
.label("Primary")
.placeholder("Primary textarea")
.rows(3)
.into_any_element(),
TextArea::new(self.demo_text("ta-secondary", "", cx))
.label("Secondary")
.placeholder("Secondary textarea")
.variant(FieldVariant::Secondary)
.rows(3)
.into_any_element(),
])Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.
use herogpui::prelude::{FieldVariant, Surface, TextArea};
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;
gpui::div()
.flex()
.flex_col()
.w(px(256.))
.gap(px(12.))
.children(vec![Surface::new()
.padding(px(24.))
.gap(px(16.))
.child(
TextArea::new(self.demo_text("ta-surface", "", cx))
.label("Notes")
.placeholder("Describe your product")
.variant(FieldVariant::Secondary)
.rows(3),
)
.into_any_element()])Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.
use herogpui::prelude::TextArea;
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;
gpui::div()
.flex()
.flex_col()
.items_start()
.justify_center()
.gap(px(12.))
.children(vec![TextArea::new(self.demo_text("ta-full", "", cx))
.label("Notes")
.placeholder("Full width textarea")
.rows(3)
.full_width()
.into_any_element()])Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.
use herogpui::prelude::{ActiveTheme, TextArea};
use herogpui::gpui::prelude::*;
use herogpui::gpui::{App, px};
use herogpui::gpui;
let ta_controlled = self
.demo_text("ta-controlled", "", cx)
.read(cx)
.value()
.to_owned();
gpui::div()
.flex()
.flex_col()
.items_start()
.justify_center()
.gap(px(12.))
.children(vec![
gpui::div()
.w(px(256.))
.flex()
.flex_col()
.child(TextArea::new(self.demo_text("ta-controlled", "", cx))
.label("Notes")
.placeholder("Compose an announcement...")
.rows(3)
.on_change(|_, _, _| {}))
.into_any_element(),
para(&format!("{} characters", ta_controlled.chars().count()), cx),
])Also calls para (included when you copy).
Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.
use herogpui::prelude::TextArea;
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;
gpui::div()
.flex()
.flex_col()
.w(px(256.))
.gap(px(12.))
.children(vec![
TextArea::new(self.demo_text("ta-one-row-floor", "", cx))
.label("One row (38px minimum)")
.placeholder("A compact note")
.rows(1)
.into_any_element(),
TextArea::new(self.input_bio.clone())
.label("Six rows")
.placeholder("Write out the full meeting notes...")
.rows(6)
.into_any_element(),
])Helpers used by these examples
Plain functions over the public API, defined once here and copied with each example that calls them.
fn para(text: &str, cx: &App) -> gpui::AnyElement {
let colors = cx.colors();
gpui::div()
.text_size(px(14.5))
.line_height(px(24.))
.text_color(colors.foreground)
.max_w(px(720.))
.child(text.to_owned())
.into_any_element()
}Anatomy
Rust types
Text Area is assembled from these builders. The API reference lists each one.
Customization
Shared appearance belongs on ThemeBuilder::components and .recipe("name"). Typed builders change how Text Area looks at one call site. Every builder also carries sx for placement, width and flex: it takes GPUI's own styling methods and refines them over the component's root after the theme, so an instance override wins. Behaviour builders live in the API reference below.
Styling
| Method | Values | Description |
|---|---|---|
full_width() | true | false | Stretches to the available container width. |
variant(FieldVariant) | FieldVariant::Primary | FieldVariant::Secondary | Primary field chrome or the lower-emphasis surface variant. |
// The one slot for caller-owned low-level styling: GPUI's
// styling methods, refined over the root element last.
.sx(|el| {
el.bg(gpui::rgba(0xffa500ff)) // background
.text_color(gpui::rgba(0x000000ff)) // text
.w(gpui::px(13.)) // size
.h(gpui::px(12.))
})API reference
Against HeroUI v3.2.6: 20 entries ported, 1 partial, 3 not ported. Partial rows are marked in the tables; entries not ported are listed under each table with the reason.
Builders
| Builder | Values | Default | Description |
|---|---|---|---|
rows( | number | 3 | Sets the visible height from the requested line count and field padding. |
cols(Partial | number | — | GPUI has no ch unit, so columns use an 8px character-advance approximation. |
value( | string | — | Seeds the owned InputState with the controlled value on the first render; InputState::set_value updates it afterwards. |
default_value( | string | — | Seeds the uncontrolled InputState once. |
on_change( | Fn( | — | Reports accepted text and newline edits without reporting rejected maxLength edits. |
placeholder( | string | — | Placeholder shown while empty and unfocused. |
is_disabled( | true | | false | Removes focus and editing and applies disabled opacity. |
is_read_only( | true | | false | Keeps focus and selection while suppressing edits. |
is_required( | true | | false | Participates in the HeroGPUI form validity registry. |
name( | string | — | Submission name stored with the current multi-line value. |
max_length( | number | — | Rejects character and newline edits beyond the limit without reporting an unchanged value. |
min_length( | number | — | Marks a non-empty value invalid below the character minimum. |
full_width( | true | | false | Stretches to the available container width. |
focus_ring( | true | | true | GPUI extension: hides only the visual focus ring while retaining focus and editing. |
variant( | FieldVariant:: | FieldVariant:: | Primary field chrome or the lower-emphasis surface variant. |
Not ported3 HeroUI entries not ported
| HeroUI v3 | Why it is not ported |
|---|---|
TextArea.className | Tailwind class merging has no GPUI analogue. |
TextArea.autoComplete | Browser autofill hints have no desktop GPUI equivalent. |
TextArea.wrap | GPUI provides one visual wrapping mode and does not inject hard line breaks for submission. |
Parts
| Part | Description |
|---|---|
TextArea | Multi-line editable field backed by InputState with caret, selection and validation. |
States
| State | Builder | Description |
|---|---|---|
Hover | inner Input hover | Changes field background and border while unfocused. |
Focused | inner Input focus | Draws focused field background, border and ring. |
Focus visible | focused field treatment | Pinned CSS adds no rule beyond the focused field treatment. |
Invalid | inner Input validity | Uses invalid field ring and focused background. |
Disabled | is_disabled(bool) | Applies theme disabled opacity and removes editing and focus. |