Skip to main content
Version: v8.1.0-alpha.2

ontario-textarea

Use a text area when you want the user to enter more than a single line of information.

Usage guidance

Please refer to the Ontario Design System for current documentation guidance.

Disabled and read-only states

This component intentionally does not provide readOnly or disabled props.

Disabling form controls can create accessibility and usability barriers, and often does not explain what the user needs to fix.

Instead:

  • keep controls and submission actions available
  • use validation and error messaging to clearly identify missing or invalid input

For implementation examples, see Error messaging.

Source: https://designsystem.ontario.ca/components/detail/buttons.html#disabled-buttons

Configuration

Once the component package has been installed (see Ontario Design System Component Library for installation instructions), the textarea component can be added directly into the project's code, and can be customized by updating the properties outlined here. Additional information on custom types for header properties are outlined here. Please see the examples below for how to configure the component.

Examples

Example of a bare-bones textarea component where the user is passing the name which is the value used to reference form data after a form is submitted. The elementId is also being passed in as the unique identifier of the textarea.

<ontario-textarea caption="Comments" name="comments" element-id="form-comments"></ontario-textarea>

To mark a textarea as required, add the required attribute to the component.

<ontario-textarea
caption="Comments"
name="comments"
element-id="form-comments"
required="true"
onBlur="exampleFunction()"
></ontario-textarea>

Forms

The ontario-textarea supports integration with native HTML <form> elements. This element integrates with the underlying browser form API and should work the same as a <textarea>.

The component's host value stays in sync as users interact with the textarea. The component updates that value, updates the form value, and exposes the current content through host-native events.

<form>
<!-- Add an ontario-textarea -->
<ontario-textarea name="textarea-1" caption="Text area"></ontario-textarea>

<!-- Submit the form with a submit button -->
<ontario-button type="primary" html-type="submit">Submit</ontario-button>
</form>

Remember to set the name attribute as this is used to identify the field when submitting the form.

Event model

Each event emitted by the component uses the CustomEvent type to emit a custom event to help communicate what the component is doing. To access the data emitted by the component within the CustomEvent type use the CustomEvent.detail property.

Eg. To access the value of any input entered into this component from the inputOnInput event, use the following code to wire up to listen for the the inputOnInput event.

<ontario-textarea id="textarea-1" name="textarea-1" caption="Text area"></ontario-textarea>
<script>
// Note: this waits for the page and components to load before
// locating the component.
window.onload = () => {
const textarea1 = document.getElementById('textarea-1');
textarea1.addEventListener('inputOnInput', (event) => {
console.log('OnInput detail:', event.detail);
});
};
</script>

If the letter i is typed into textarea-1, the value of event.detail is the object emitted along with the inputOnInput event.

{ id: "910b4a52-c005-4fb6-9b6e-fd7370a00b25", value: "i", inputType: "insertText" }

See the Events table to learn more about the available custom events from the component and what the type of CustomEvent.detail will be.

Native input and change events

The component uses a ShadowDOM to maintain encapsulation, however, this changes how the events flow from the inside of the component to the outside in the DOM.

The component keeps its value in sync as the internal <textarea> changes.

Events, such as the native input event, deliver data from inside of the component and flow up the event stack as expected.

This isn't the case for the native change event, this event hits the ShadowDOM boundary and stops propagating. The implication of this is that it can't be listened for outside the component. To attempt to overcome this, a synthetic change event is generated and emitted. The original change event is available via the detail property on the emitted event.

If you are observing the component from the outside, prefer reading the current textarea content from event.target.value on the host input or change event. Use inputOnInput and inputOnChange when you specifically want the component's richer custom event detail.

document.querySelector('ontario-textarea').addEventListener('input', (event) => {
console.log(event.target.value);
});

document.querySelector('ontario-textarea').addEventListener('change', (event) => {
console.log(event.target.value);
});

When using libraries that listen for events, this process may not work with them and a workaround might be required depending on the framework or library in use.

Error messaging

Use validation and error messaging to help users understand what needs to be corrected.

Setting an error message

Set the errorMessage property on ontario-textarea to display an error state and message. You can also listen for inputErrorOccurred to react to error updates in application code.

Static vs live validation

Use a static errorMessage when validation happens on submit (for example, after a form post or submit handler check).

Use live validation when you want real-time feedback as users interact (for example, on change or blur).

For more guidance, visit the Error messaging guidance page.

<ontario-textarea id="comments" name="comments" caption="Comments" required></ontario-textarea>
<script>
window.addEventListener('load', () => {
const textarea = document.getElementById('comments');
textarea.addEventListener('inputOnBlur', () => {
textarea.errorMessage = textarea.value?.trim() ? '' : 'Enter your comments before continuing.';
});
});
</script>

Live validation

Keep the control available and validate content on interaction (for example, on blur or submit). When validation fails, set a contextual error message that explains how to fix the issue.

Custom property types

caption

The caption property is used to render the legend for the ontario-textarea. It can be passed either a string or an object. If no captionType needs to be specified, it can be passed as a string.

caption='{ "captionText": "Textarea label", "captionType": "default" }'
Property nameTypeDefaultDescription
captionTextstringText to display as the radio textarea question
captionType"default" | "large"| "heading"defaultThe type of legend to display for the textarea question. This is optional, and if no information is provided, it will default to the default type.

hintExpander

The hintExpander property is used to include the Hint Expander component underneath the input label. This is passed in as an object with key-value pairs.

hintExpander='{ "hint": "This is the hint expander title", "content": "This is the hint expander content - it is only visible when the hint expander title (hint) is toggled" }'
Property nameTypeDescription
hintstringText to display as the hint expander label/title. When toggled, it will display/hide the hintExpander content
contentstringText to display as the content of the hint expander

Accessibility

  • An element-id attribute is necessary to allow the textarea to be associated with a label element
  • A name attribute needs to be set to be submitted to the server when the form is submitted.

Technical Note: SSR (Server-Side Rendering) Considerations

The Ontario Textarea component supports server-side rendering, with a few considerations:

  • Language prop: Language change events only fire in the browser after hydration. To ensure the correct language is rendered during SSR, pass the desired language explicitly as a prop.
  • Dynamic ID generation: If elementId is not passed, a UUID is generated at runtime. To prevent hydration mismatches between server and client, explicitly pass a stable elementId.
  • Hint text and accessibility IDs: If using ontario-hint-text, note that the aria-describedby reference is resolved after hydration. Make sure this does not impact critical accessibility paths in your application.
  • Form participation: This component uses the Form-Associated Custom Elements API (@AttachInternals) to participate in native form submission. During SSR, it renders with the expected <textarea> structure and can support straightforward form submission when name, language, and elementId are stable. Enhanced validation, custom validators, and the component's event model become available after hydration.
  • Hydrated-only behaviour: If your application depends on custom events or runtime validation, use the event examples below and treat that behaviour as hydrated-only.
  • Framework guidance: Use the HTML <form> example above for native submit or Next.js server-action style flows. For App Router setup details, follow the Next.js integration guide.

SSR-safe example:

<OntarioTextarea name="comments" language="en" elementId="comments"></OntarioTextarea>

Overview

Ontario Textarea captures multi-line text input.

This component intentionally does not expose readOnly or disabled props.

To support accessible and understandable form completion:

  • keep form fields and submission actions available
  • use validation and error messaging to guide corrections

For component guidance, see:

Disabled/read-only policy source:

Properties

PropertyAttributeDescriptionTypeDefault
captioncaptionThe text to display as the textarea label.Caption | stringundefined
customOnBlurcustom-on-blurUsed to add a custom function to the textarea onBlur event.((event: Event) => void) | undefinedundefined
customOnChangecustom-on-changeUsed to add a custom function to the textarea onChange event.((event: Event) => void) | undefinedundefined
customOnFocuscustom-on-focusUsed to add a custom function to the textarea onFocus event.((event: Event) => void) | undefinedundefined
customOnInputcustom-on-inputUsed to add a custom function to the textarea onInput event.((event: Event) => void) | undefinedundefined
elementIdelement-idThe unique identifier of the textarea. This is optional - if no ID is passed, one will be generated.string | undefinedundefined
errorMessageerror-messageSet this to display an error messagestring | undefinedundefined
hintExpanderhint-expanderUsed to include the ontario-hint-expander component for the textarea component. This is passed in as an object with key-value pairs. This is optional.HintExpander | string | undefinedundefined
hintTexthint-textUsed to include the ontario-hint-text component for the textarea. This is optional.Hint | string | undefinedundefined
languagelanguageThe language of the component. This is used for translations, and is by default set through event listeners checking for a language property from the header. If no language is passed, it will default to English."en" | "fr" | undefinedundefined
namenameThe name assigned to the textarea. The name value is used to reference form data after a form is submitted.stringundefined
requiredrequiredThis is used to determine whether the textarea is required or not. This prop also gets passed to the InputCaption utility to display either an optional or required flag in the label. If no prop is set, it will default to false (optional).boolean | undefinedfalse
valuevalueThe textarea content value.string | undefinedundefined

Events

EventDescriptionType
inputErrorOccurredEmitted when an error message is reported to the component.CustomEvent<{ inputId: string; errorMessage: string; }>
inputOnBlurEmitted when a keyboard input event occurs when an input has lost focus.CustomEvent<InputInteractionEvent & { focused: boolean; }>
inputOnChangeEmitted when a keyboard input or mouse event occurs when an input has been changed.CustomEvent<{ id?: string | undefined; value?: string | undefined; }>
inputOnFocusEmitted when a keyboard input event occurs when an input has gained focus.CustomEvent<InputInteractionEvent & { focused: boolean; }>
inputOnInputEmitted when a input event occurs when an input has been changed.CustomEvent<InputInteractionEvent & { inputType?: string | undefined; }>

Dependencies

Depends on

Graph


Built with StencilJS