Textarea
A textarea lets users enter multiple lines of text, such as when answering an open-ended question.
<div class="ons-field">
<label class="ons-label ons-label--with-description" for="textarea">Please provide some feedback</label>
<span id="description-hint" class="ons-label__description ons-input--with-description">For example, describe any difficulties you experienced in the use of this service</span>
<textarea id="textarea" class="ons-input ons-input--textarea " name="feedback" rows="8"></textarea>
</div>
{% from "components/textarea/_macro.njk" import onsTextarea %}
{{
onsTextarea({
"id": "textarea",
"name": "feedback",
"label": {
"text": "Please provide some feedback",
"description": "For example, describe any difficulties you experienced in the use of this service"
}
})
}}
{% macro onsTextarea(params) %}
{% from "components/mutually-exclusive/_macro.njk" import onsMutuallyExclusive %}
{% from "components/field/_macro.njk" import onsField %}
{% from "components/label/_macro.njk" import onsLabel %}
{% from "components/char-check-limit/_macro.njk" import onsCharLimit %}
{% set field %}
{% set textareaExclusiveClass = " ons-js-exclusive-group-item" if params.mutuallyExclusive else "" %}
{% if params.label is defined and params.label %}
{{ onsLabel({
"for": params.id,
"text": params.label.text,
"description": params.label.description,
"classes": params.label.classes
}) }}
{% endif %}
<textarea
id="{{ params.id }}"
class="ons-input ons-input--textarea {% if params.error is defined and params.error %} ons-input--error {% endif %}{% if params.charCheckLimit is defined and params.charCheckLimit and params.charCheckLimit.limit is defined and params.charCheckLimit.limit %} ons-js-char-limit-input{% endif %}{{ textareaExclusiveClass }} {{ params.classes }} {% if params.width is defined and params.width %}ons-input--w-{{ params.width }}{% endif %}"
name="{{ params.name }}"
rows="{{ params.rows | default(8) }}"
{% if params.charCheckLimit is defined and params.charCheckLimit and params.charCheckLimit.limit is defined and params.charCheckLimit.limit %}
maxlength="{{ params.charCheckLimit.limit }}"
data-char-limit-ref="{{ params.id }}-lim-remaining"
aria-describedby="{{ params.id }}-lim-remaining"
{% endif %}
{% if params.attributes is defined and params.attributes %}{% for attribute, value in (params.attributes.items() if params.attributes is mapping and params.attributes.items else params.attributes) %}{{ attribute }}{% if value is defined and value %}="{{ value }}"{% endif %} {% endfor %}{% endif %}
>{{ params.value }}</textarea>
{% if params.charCheckLimit is defined and params.charCheckLimit and params.charCheckLimit.limit is defined and params.charCheckLimit.limit %}
{% call onsCharLimit({
"id": params.id ~ "-lim",
"limit": params.charCheckLimit.limit,
"charCountSingular": params.charCheckLimit.charCountSingular,
"charCountPlural": params.charCheckLimit.charCountPlural
}) %}
{% endcall %}
{% endif %}
{% endset %}
{% if params.mutuallyExclusive is defined and params.mutuallyExclusive %}
{% call onsMutuallyExclusive({
"id": params.fieldId,
"classes": params.fieldClasses,
"legend": params.legend,
"legendClasses": params.legendClasses,
"description": params.description,
"dontWrap": params.dontWrap,
"legendIsQuestionTitle": params.legendIsQuestionTitle,
"checkbox": params.mutuallyExclusive.checkbox,
"or": params.mutuallyExclusive.or,
"deselectMessage": params.mutuallyExclusive.deselectMessage,
"deselectGroupAdjective": params.mutuallyExclusive.deselectGroupAdjective,
"deselectCheckboxAdjective": params.mutuallyExclusive.deselectCheckboxAdjective,
"error": params.error
}) %}
{% call onsField({
"error": params.error
}) %}
{{ field | safe }}
{% endcall %}
{% endcall %}
{% else %}
{% call onsField({
"id": params.fieldId,
"classes": params.fieldClasses,
"dontWrap": params.dontWrap,
"error": params.error
}) %}
{{ field | safe }}
{% endcall %}
{% endif %}
{% endmacro %}
When to use this component
Use the textarea component when you need the user to enter text that’s longer than one line, for example, to answer an open-ended question.
A good use of this component is to ask the user for feedback about your service by means of the phase banner.
When not to use this component
Open-ended questions can be difficult for users to answer, so consider breaking down the question into simpler questions that can be answered using a single line input or by selecting an answer using, for example, radios.
How to use this component
All textarea components must have a visible label, with or without a description.
Textareas should be appropriately sized to help the user understand what they should enter by making them the right size for the content they are intended for.
Use appropriately sized textareas
Where possible, you should make the textareas proportional to the amount of text you expect users to enter.
By default, the textarea component will fill the width of its container and has a default height of 8 lines of text.
A width constraint class can be used to make the width of textarea smaller, or the rows
parameter can be set to make the height of the textarea larger.
Variants
Character limit
The character limit counter is displayed when the charCheckLimit
object is defined with params limit
, charCountSingular
, charCountPlural
parameters.
<div class="ons-field">
<label class="ons-label ons-label--with-description" for="textarea-char-limit">Please provide some feedback</label>
<span id="description-hint" class="ons-label__description ons-input--with-description">For example, describe any difficulties you experienced in the use of this service</span>
<textarea id="textarea-char-limit" class="ons-input ons-input--textarea ons-js-char-limit-input ons-input--w-30" name="feedback-limited" rows="8" maxlength="200" data-char-limit-ref="textarea-char-limit-lim-remaining" aria-describedby="textarea-char-limit-lim-remaining"></textarea>
<span id="textarea-char-limit-lim-remaining" class="ons-input__limit ons-u-fs-s--b ons-u-d-no ons-u-mt-xs" data-charcount-singular="You have {x} character remaining" data-charcount-plural="You have {x} characters remaining" data-charcount-limit-singular="" data-charcount-limit-plural="">
</span>
</div>
{% from "components/textarea/_macro.njk" import onsTextarea %}
{{
onsTextarea({
"id": "textarea-char-limit",
"name": "feedback-limited",
"width": "30",
"label": {
"text": "Please provide some feedback",
"description": "For example, describe any difficulties you experienced in the use of this service"
},
"charCheckLimit": {
"limit": 200,
"charCountSingular": "You have {x} character remaining",
"charCountPlural": "You have {x} characters remaining"
}
})
}}
{% macro onsTextarea(params) %}
{% from "components/mutually-exclusive/_macro.njk" import onsMutuallyExclusive %}
{% from "components/field/_macro.njk" import onsField %}
{% from "components/label/_macro.njk" import onsLabel %}
{% from "components/char-check-limit/_macro.njk" import onsCharLimit %}
{% set field %}
{% set textareaExclusiveClass = " ons-js-exclusive-group-item" if params.mutuallyExclusive else "" %}
{% if params.label is defined and params.label %}
{{ onsLabel({
"for": params.id,
"text": params.label.text,
"description": params.label.description,
"classes": params.label.classes
}) }}
{% endif %}
<textarea
id="{{ params.id }}"
class="ons-input ons-input--textarea {% if params.error is defined and params.error %} ons-input--error {% endif %}{% if params.charCheckLimit is defined and params.charCheckLimit and params.charCheckLimit.limit is defined and params.charCheckLimit.limit %} ons-js-char-limit-input{% endif %}{{ textareaExclusiveClass }} {{ params.classes }} {% if params.width is defined and params.width %}ons-input--w-{{ params.width }}{% endif %}"
name="{{ params.name }}"
rows="{{ params.rows | default(8) }}"
{% if params.charCheckLimit is defined and params.charCheckLimit and params.charCheckLimit.limit is defined and params.charCheckLimit.limit %}
maxlength="{{ params.charCheckLimit.limit }}"
data-char-limit-ref="{{ params.id }}-lim-remaining"
aria-describedby="{{ params.id }}-lim-remaining"
{% endif %}
{% if params.attributes is defined and params.attributes %}{% for attribute, value in (params.attributes.items() if params.attributes is mapping and params.attributes.items else params.attributes) %}{{ attribute }}{% if value is defined and value %}="{{ value }}"{% endif %} {% endfor %}{% endif %}
>{{ params.value }}</textarea>
{% if params.charCheckLimit is defined and params.charCheckLimit and params.charCheckLimit.limit is defined and params.charCheckLimit.limit %}
{% call onsCharLimit({
"id": params.id ~ "-lim",
"limit": params.charCheckLimit.limit,
"charCountSingular": params.charCheckLimit.charCountSingular,
"charCountPlural": params.charCheckLimit.charCountPlural
}) %}
{% endcall %}
{% endif %}
{% endset %}
{% if params.mutuallyExclusive is defined and params.mutuallyExclusive %}
{% call onsMutuallyExclusive({
"id": params.fieldId,
"classes": params.fieldClasses,
"legend": params.legend,
"legendClasses": params.legendClasses,
"description": params.description,
"dontWrap": params.dontWrap,
"legendIsQuestionTitle": params.legendIsQuestionTitle,
"checkbox": params.mutuallyExclusive.checkbox,
"or": params.mutuallyExclusive.or,
"deselectMessage": params.mutuallyExclusive.deselectMessage,
"deselectGroupAdjective": params.mutuallyExclusive.deselectGroupAdjective,
"deselectCheckboxAdjective": params.mutuallyExclusive.deselectCheckboxAdjective,
"error": params.error
}) %}
{% call onsField({
"error": params.error
}) %}
{{ field | safe }}
{% endcall %}
{% endcall %}
{% else %}
{% call onsField({
"id": params.fieldId,
"classes": params.fieldClasses,
"dontWrap": params.dontWrap,
"error": params.error
}) %}
{{ field | safe }}
{% endcall %}
{% endif %}
{% endmacro %}
How to check a textarea
To help users enter something in a required textarea, you should:
- check they have entered something in the textarea
- show an error message if they have not entered anything
Error messages
Use the correct errors pattern and show the error details above the textarea.
<div class="ons-panel ons-panel--error ons-panel--no-title" id="feedback-error">
<span class="ons-u-vh">Error: </span>
<div class="ons-panel__body">
<p class="ons-panel__error">
<strong>Enter your feedback</strong>
</p>
<div class="ons-field">
<label class="ons-label ons-label--with-description" for="textarea">Please provide some feedback</label>
<span id="description-hint" class="ons-label__description ons-input--with-description">For example, describe any difficulties you experienced in the use of this service</span>
<textarea id="textarea" class="ons-input ons-input--textarea ons-input--error " name="feedback" rows="8"></textarea>
</div>
</div>
</div>
{% from "components/textarea/_macro.njk" import onsTextarea %}
{{
onsTextarea({
"id": "textarea",
"name": "feedback",
"label": {
"text": "Please provide some feedback",
"description": "For example, describe any difficulties you experienced in the use of this service"
},
"error": {
"id": "feedback-error",
"text": "Enter your feedback",
"dsExample": isPatternLib
}
})
}}
{% macro onsTextarea(params) %}
{% from "components/mutually-exclusive/_macro.njk" import onsMutuallyExclusive %}
{% from "components/field/_macro.njk" import onsField %}
{% from "components/label/_macro.njk" import onsLabel %}
{% from "components/char-check-limit/_macro.njk" import onsCharLimit %}
{% set field %}
{% set textareaExclusiveClass = " ons-js-exclusive-group-item" if params.mutuallyExclusive else "" %}
{% if params.label is defined and params.label %}
{{ onsLabel({
"for": params.id,
"text": params.label.text,
"description": params.label.description,
"classes": params.label.classes
}) }}
{% endif %}
<textarea
id="{{ params.id }}"
class="ons-input ons-input--textarea {% if params.error is defined and params.error %} ons-input--error {% endif %}{% if params.charCheckLimit is defined and params.charCheckLimit and params.charCheckLimit.limit is defined and params.charCheckLimit.limit %} ons-js-char-limit-input{% endif %}{{ textareaExclusiveClass }} {{ params.classes }} {% if params.width is defined and params.width %}ons-input--w-{{ params.width }}{% endif %}"
name="{{ params.name }}"
rows="{{ params.rows | default(8) }}"
{% if params.charCheckLimit is defined and params.charCheckLimit and params.charCheckLimit.limit is defined and params.charCheckLimit.limit %}
maxlength="{{ params.charCheckLimit.limit }}"
data-char-limit-ref="{{ params.id }}-lim-remaining"
aria-describedby="{{ params.id }}-lim-remaining"
{% endif %}
{% if params.attributes is defined and params.attributes %}{% for attribute, value in (params.attributes.items() if params.attributes is mapping and params.attributes.items else params.attributes) %}{{ attribute }}{% if value is defined and value %}="{{ value }}"{% endif %} {% endfor %}{% endif %}
>{{ params.value }}</textarea>
{% if params.charCheckLimit is defined and params.charCheckLimit and params.charCheckLimit.limit is defined and params.charCheckLimit.limit %}
{% call onsCharLimit({
"id": params.id ~ "-lim",
"limit": params.charCheckLimit.limit,
"charCountSingular": params.charCheckLimit.charCountSingular,
"charCountPlural": params.charCheckLimit.charCountPlural
}) %}
{% endcall %}
{% endif %}
{% endset %}
{% if params.mutuallyExclusive is defined and params.mutuallyExclusive %}
{% call onsMutuallyExclusive({
"id": params.fieldId,
"classes": params.fieldClasses,
"legend": params.legend,
"legendClasses": params.legendClasses,
"description": params.description,
"dontWrap": params.dontWrap,
"legendIsQuestionTitle": params.legendIsQuestionTitle,
"checkbox": params.mutuallyExclusive.checkbox,
"or": params.mutuallyExclusive.or,
"deselectMessage": params.mutuallyExclusive.deselectMessage,
"deselectGroupAdjective": params.mutuallyExclusive.deselectGroupAdjective,
"deselectCheckboxAdjective": params.mutuallyExclusive.deselectCheckboxAdjective,
"error": params.error
}) %}
{% call onsField({
"error": params.error
}) %}
{{ field | safe }}
{% endcall %}
{% endcall %}
{% else %}
{% call onsField({
"id": params.fieldId,
"classes": params.fieldClasses,
"dontWrap": params.dontWrap,
"error": params.error
}) %}
{{ field | safe }}
{% endcall %}
{% endif %}
{% endmacro %}
If the textarea is empty
Use “Enter [whatever type of text is being asked for]”.
For example, “Enter your feedback” or “Enter a job title”.
Research on this component
The textarea component was last user tested between February and September 2020 during research for Census 2021. The following findings were reported:
- along with the size of the textarea, the character limit helps users know how long their answer should be
- the character counter is often not noticed until the user starts to enter text
- users that look down at a keyboard while they type may not notice the character counter
- users prefer a limit on characters that can be entered as it prevents them entering far more text than is needed
- the change from black to red text when the character limit is reached helps users notice the counter
Help improve this component
Let us know how we could improve this component or share your user research findings. Discuss the ‘Textarea’ component on GitHub