Area where user can enter larger amounts of text. Commonly used in forms.
Add an id to your Textarea so that clicking the label will move focus directly to the input.
<%= pb_rails("textarea", props: { label: "Label", rows: 4, id: "default-example-1" }) %> <br/> <%= pb_rails("textarea", props: { label: "Label", placeholder: "Placeholder text", id: "default-example-2" }) %> <br/> <%= pb_rails("textarea", props: { label: "Label", name: "comment", value: "Default value text", id: "default-example-3" }) %>
<%= pb_rails("textarea", props: { label: "auto", placeholder: "Resize Auto", resize: "auto" }) %> <br/> <%= pb_rails("textarea", props: { label: "vertical", placeholder: "Resize Vertical", resize: "vertical" }) %> <br/> <%= pb_rails("textarea", props: { label: "both", placeholder: "Resize Both", resize: "both" }) %> <br/> <%= pb_rails("textarea", props: { label: "horizontal", placeholder: "Resize Horizontal", resize: "horizontal" }) %>
Textarea w/ Error shows that the input must be filled out (i.e. when used in a form it signals a user to fix an error).
<% text_area_2_value = "Counting characters!" %> <% text_area_3_value = "This counter prevents the user from exceeding the maximum number of allowed characters. Just try it!" %> <% text_area_4_value = "This counter alerts the user that they have exceeded the maximum number of allowed characters." %> <%= pb_rails("textarea", props: { character_count: 0, id: "text-area-1", label: "Count Only", onkeyup: "handleChange1(event)", }) %> <%= pb_rails("textarea", props: { character_count: text_area_2_value.length, id: "text-area-2", label: "Max Characters", max_characters: 100, onkeyup: "handleChange2(event, 100)", value: text_area_2_value, }) %> <%= pb_rails("textarea", props: { character_count: text_area_3_value.length, id: "text-area-3", label: "Max Characters w/ Blocker", max_characters: 100, onkeyup: "handleChange3(event, 100)", value: text_area_3_value, }) %> <%= pb_rails("textarea", props: { character_count: text_area_4_value.length, error: "Too many characters!", id: "text-area-4", label: "Max Characters w/ Error", max_characters: 75, onkeyup: "handleChange4(event, 75)", value: text_area_4_value, }) %> <script type="text/javascript"> const characterCount1 = document.querySelector("#text-area-1 .pb_caption_kit_xs") const characterCount2 = document.querySelector("#text-area-2 .pb_caption_kit_xs") const characterCount3 = document.querySelector("#text-area-3 .pb_caption_kit_xs") const characterCount4 = document.querySelector("#text-area-4 .pb_caption_kit_xs") const textArea3 = document.querySelector("#text-area-3 textarea") const textArea4 = document.querySelector("#text-area-4 textarea") const handleChange1 = (event) => { characterCount1.innerHTML = event.target.value.length } const handleChange2 = (event, maxCharacters) => { characterCount2.innerHTML = `${event.target.value.length} / ${maxCharacters}` } const handleChange3 = (event, maxCharacters) => { if (event.target.value.length > maxCharacters) { textArea3.value = event.target.value.substring(0, maxCharacters) } characterCount3.innerHTML = `${textArea3.value.length} / ${maxCharacters}` } const handleChange4 = (event, maxCharacters) => { characterCount4.innerHTML = `${textArea4.value.length} / ${maxCharacters}` } </script>
Use the emojiMask / emoji_mask prop to prevent users from entering emoji characters (🐸 🐈 🏄♂️) in typed or pasted content. It allows accented characters and other non-ASCII letters (é, ü, 文).
The requiredIndicator/required_indicator prop displays a red asterisk (*) next to the label, visually indicating that the field is required. This is purely visual and does not enforce validation.
You can use requiredIndicator/required_indicator with any validation approach: HTML5 validation via the required prop, client-side validation, or backend validation. For this reason, it works independently and doesn't need to be paired with the required prop.
Use the input_options / inputOptions prop to pass additional attributes directly to the underlying <textarea> element instead of the outer wrapper. This is useful for applying data attributes, custom IDs, ARIA attributes, or other HTML attributes that need to be on the textarea element itself.
Additional HTML attributes (e.g. data or ARIA attributes) can also be passed directly to the <textarea> via input_options.
<%= pb_rails("textarea", props: { label: "ID on Container", id: "container-id", name: "comment", rows: 4 }) %> <br/> <%= pb_rails("textarea", props: { label: "ID on Textarea via input_options", input_options: { id: "textarea-id" }, name: "comment", rows: 4 }) %> <br/> <%= pb_rails("textarea", props: { label: "Both Container and Textarea IDs", id: "container-id-2", input_options: { id: "textarea-id-2" }, name: "comment", rows: 4 }) %> <br/> <%= pb_rails("textarea", props: { label: "Data and ARIA Attributes", name: "description", rows: 4, input_options: { 'aria-label': "Enter description", 'aria-describedby': "help-text", data: { controller: "textarea", action: "focus->handleFocus" }, id: "description-textarea" } }) %>
Do not use for small text amounts (use Text Input instead). Avoid using textarea without validation if it is required and using with validation if not required.
| Props | Type | Values |
|---|---|---|
align_content |
enum | responsive
|
start
end
center
spaceBetween
spaceAround
spaceEvenly
|
align_items |
enum | responsive
|
start
end
center
|
border_radius |
enum
|
none
xs
sm
md
lg
xl
rounded
|
cursor |
enum
|
auto
default
none
contextMenu
help
pointer
progress
wait
cell
|
dark |
boolean
|
true
false
|
flex |
enum | responsive
|
auto
initial
0
1
2
3
4
5
6
7
8
9
10
11
12
none
|
flex_direction |
enum | responsive
|
row
column
rowReverse
columnReverse
|
flex_wrap |
enum | responsive
|
wrap
nowrap
wrapReverse
|
justify_content |
enum | responsive
|
start
end
center
spaceBetween
spaceAround
spaceEvenly
|
line_height |
enum
|
loosest
looser
loose
normal
tight
tighter
tightest
|
margin_right |
array
|
none
xxs
xs
sm
md
lg
xl
|
margin_left |
array
|
none
xxs
xs
sm
md
lg
xl
|
margin_top |
array
|
none
xxs
xs
sm
md
lg
xl
|
margin_bottom |
array
|
none
xxs
xs
sm
md
lg
xl
|
margin_x |
array
|
none
xxs
xs
sm
md
lg
xl
|
margin_y |
array
|
none
xxs
xs
sm
md
lg
xl
|
margin |
array
|
none
xxs
xs
sm
md
lg
xl
|
width |
string
|
|
min_width |
string
|
|
max_width |
string
|
|
gap |
string | responsive
|
|
column_gap |
string | responsive
|
|
row_gap |
string | responsive
|
|
number_spacing |
enum
|
tabular
|
order |
enum | responsive
|
none
first
1
2
3
4
5
6
7
8
9
10
11
12
|
overflow_x |
enum
|
scroll
visible
hidden
auto
|
overflow_y |
enum
|
scroll
visible
hidden
auto
|
overflow |
enum
|
scroll
visible
hidden
auto
|
padding_right |
array
|
none
xxs
xs
sm
md
lg
xl
|
padding_left |
array
|
none
xxs
xs
sm
md
lg
xl
|
padding_top |
array
|
none
xxs
xs
sm
md
lg
xl
|
padding_bottom |
array
|
none
xxs
xs
sm
md
lg
xl
|
padding_x |
array
|
none
xxs
xs
sm
md
lg
xl
|
padding_y |
array
|
none
xxs
xs
sm
md
lg
xl
|
padding |
array
|
none
xxs
xs
sm
md
lg
xl
|
position |
enum
|
relative
absolute
fixed
sticky
static
|
shadow |
enum
|
none
deep
deeper
deepest
|
text_align |
enum | responsive
|
start
end
left
right
center
justify
justifyAll
matchParent
|
truncate |
enum
|
none
1
2
3
4
5
|
vertical_align |
enum | responsive
|
baseline
super
top
middle
bottom
sub
text-top
text-bottom
|
z_index |
enum | responsive
|
1
2
3
4
5
6
7
8
9
10
max
|
top |
enum | object
|
xxs
xs
sm
md
lg
xl
xxl
|
inset |
boolean
|
true
false
|
right |
enum | object
|
xxs
xs
sm
md
lg
xl
xxl
|
bottom |
enum | object
|
xxs
xs
sm
md
lg
xl
xxl
|
left |
enum | object
|
xxs
xs
sm
md
lg
xl
xxl
|
height |
string
|
|
max_height |
string
|
|
min_height |
string
|
|
hover |
object
|
|
group_hover |
boolean
|
true
false
|
| Props | Type | Values | Default |
|---|---|---|---|
character_count |
string
|
||
disabled |
boolean
|
true
false
|
false
|
emoji_mask |
boolean
|
true
false
|
false
|
error |
string
|
||
inline |
boolean
|
true
false
|
false
|
input_options |
object
|
||
object |
string
|
||
method |
string
|
||
label |
string
|
||
max_characters |
string
|
||
placeholder |
string
|
||
value |
string
|
||
name |
string
|
||
required |
boolean
|
true
false
|
|
required_indicator |
boolean
|
true
false
|
false
|
rows |
number
|
4
|
|
resize |
enum
|
none
both
horizontal
vertical
auto
|
none
|
on_change |
reactnode
|
||
onkeyup |
string
|