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

ontario-dropdown-list

Only use a dropdown (select) list if you cannot use other form components to capture the user’s 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 dropdown list 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 dropdown list properties are outlined here. Please see the examples below for how to configure the component.

Examples

Example of a dropdown list component with no elementId or isEmptyStartOption props passed. Note that by default, an ID for the elementId will be generated if none is provided. If no isEmptyStartOption prop is provided, it will default to false and display the first option in the options list, unless one of the options has a selected attribute set to true.

<ontario-dropdown-list
name="streaming-service"
caption='{
"captionText": "Select a streaming service",
"captionType": "default"
}'
required
options='[{
"value": "netflix",
"label": "Netflix"
},
{
"value": "disney-plus",
"label": "Disney Plus"
},
{
"value": "crave",
"label": "Crave"
},
{
"value": "prime",
"label": "Prime Video"
}]'
>
</ontario-dropdown-list>

In the following example, the selected option is set using the component's value. Listen for the component input or change event to read the current selection.

<ontario-dropdown-list
id="dropdown-value-example"
name="streaming-service"
caption="Select a streaming service"
value="crave"
options='[
{ "value": "netflix", "label": "Netflix" },
{ "value": "disney-plus", "label": "Disney Plus" },
{ "value": "crave", "label": "Crave" }
]'
></ontario-dropdown-list>
<script>
document.getElementById('dropdown-value-example')?.addEventListener('change', (event) => {
console.log(event.target.value);
console.log(event.detail.value);
});
</script>

In the following example, all available props are passed through.

<ontario-dropdown-list
name="provinces-territories"
is-empty-start-option="Select"
element-id="provinces-territories"
language="en"
hint-text="Select the province or territory you currently live in."
caption='{
"captionText": "Province/territory",
"captionType": "heading"
}'
required
options='[{
"value": "alberta",
"label": "Alberta"
},
{
"value": "british-columbia",
"label": "British Columbia"
},
{
"value": "manitoba",
"label": "Manitoba"
},
{
"value": "new-brunswick",
"label": "New Brunswick"
},
{
"value": "newfoundland-and-labrador",
"label": "Newfoundland and Labrador"
},
{
"value": "nova-scotia",
"label": "Nova Scotia"
},
{
"value": "ontario",
"label": "Ontario",
"selected": true
},
{
"value": "prince-edward-island",
"label": "Prince Edward Island"
},
{
"value": "quebec",
"label": "Quebec"
},
{
"value": "saskatchewan",
"label": "Saskatchewan"
},
{
"value": "northwest-territories",
"label": "Northwest Territories"
},
{
"value": "nunavut",
"label": "Nunavut"
},
{
"value": "yukon",
"label": "Yukon"
}]'
>
</ontario-dropdown-list>

Forms

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

The component keeps its value in sync as users interact with the internal <select>. That same value is used for native form submission and for the component input and change events. When isEmptyStartOption is enabled, the start option uses an empty string value until a real option is selected. If a provided value does not match any option, the component emits a warning and falls back to the selected option, empty start option, or first available option.

<form>
<!-- Add an ontario-dropdown-list -->
<ontario-dropdown-list
name="dropdown-1"
is-empty-start-option="Select"
element-id="dropdown-1"
caption="Dropdown"
required
options='[{
"value": "alberta",
"label": "Alberta"
},
{
"value": "ontario",
"label": "Ontario",
"selected": true
},
{
"value": "quebec",
"label": "Quebec"
},
{
"value": "nunavut",
"label": "Nunavut"
}]'
>
</ontario-dropdown-list>

<!-- 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.

For most integrations, prefer the component input and change events and read the selected option from event.target.value. Those events also include event.detail.value as a convenience. Use dropdownOnChange when you specifically want the component's custom event payload.

Eg. To access the value of any change made to this component from the dropdownOnChange event, use the following code to wire up to listen for the the dropdownOnChange event.

<ontario-dropdown-list
name="dropdown-1"
id="dropdown-1"
is-empty-start-option="Select"
element-id="dropdown-1"
caption="Dropdown"
required
options='[{
"value": "ontario",
"label": "Ontario"
},
{
"value": "quebec",
"label": "Quebec"
}]'
></ontario-dropdown-list>
<script>
// Note: this waits for the page and components to load before
// locating the component.
window.onload = () => {
const dropdown1 = document.getElementById('dropdown-1');
dropdown1.addEventListener('dropdownOnChange', (event) => {
console.log('OnChange detail:', event.detail);
});
};
</script>

If an option is selected from dropdown-1, the value of event.detail is the object emitted along with the dropdownOnChange event.

{ id: "dropdown-1", value: "ontario" }

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 handles the internal <select> events and re-emits input and change events so consumers can listen on the component instead of the internal control. The current selection is available through event.target.value, and a convenience copy is also included in event.detail.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 errorMessage when selection is missing or invalid, and keep the list enabled so users can correct their choice.

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-dropdown-list
id="service-selection"
name="service-selection"
caption="Select a service"
required
options='[
{ "label": "Health card", "value": "health-card" },
{ "label": "Driver licence", "value": "driver-licence" }
]'
></ontario-dropdown-list>
<script>
window.addEventListener('load', () => {
const dropdown = document.getElementById('service-selection');
dropdown.addEventListener('inputOnBlur', () => {
dropdown.errorMessage = dropdown.value ? '' : 'Select a service to continue.';
});
});
</script>

Live validation

Keep the control available and validate selection 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

caption='{ "captionText": "Province/territory", "captionType": "heading" }'
Property nameTypeDescription
captionTextstringThe text to display as the caption (label) for the dropdown-list. This must be implemented.
captionType"default" | "large"| "heading"The type of caption to render. This is optional - if no type is passed, the "default" type will render.

Options

options='[ { "value": "netflix", "label": "Netflix" }, { "value": "disney-plus", "label": "Disney Plus" }, { "value":
"crave", "label": "Crave" }, { "value": "prime", "label": "Prime Video" } ]'
Property nameTypeDescription
valuestringThe dropdown option content value. Each value must be unique to the option.
labelstringThe text to display as the dropdown option label.
selectedbooleanA boolean value to determine whether or not the dropdown list option is pre-selected. If no selected value is set, it will be set to false.

Accessibility

  • An id attribute is necessary to allow the dropdown list to be associated with a label element. If none is provided through the elementId prop, one will be generated.
  • A name attribute needs to be set to be submitted to the server when the form is submitted.
  • Do not add any customized styles to dropdown lists - the browser's default is the most accessible.

Technical Note: SSR (Server-Side Rendering) Considerations

The Ontario Dropdown List 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 select structure and can support straightforward form submission when name, language, and elementId are stable. Required-state messaging and the component's event model become available after hydration.
  • Hydrated-only behaviour: If your application depends on emitted events or hydrated validation behaviour, use the event examples below and verify the full submit flow in the consuming application.
  • 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:

<OntarioDropdownList
name="province"
elementId="province"
language="en"
caption={{ captionText: 'Select your province', captionType: 'heading' }}
options={[
{ label: 'Ontario', value: 'on' },
{ label: 'Quebec', value: 'qc' },
]}
isEmptyStartOption="Select a province"
/>

Overview

Ontario Dropdown List presents a selectable list of predefined options.

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 for the dropdown list label.Caption | stringundefined
customOnBlurcustom-on-blurUsed to add a custom function to the dropdown onBlur event.((event: Event) => void) | undefinedundefined
customOnChangecustom-on-changeUsed to add a custom function to the dropdown onChange event.((event: Event) => void) | undefinedundefined
customOnFocuscustom-on-focusUsed to add a custom function to the dropdown onFocus event.((event: Event) => void) | undefinedundefined
elementIdelement-idThe ID for the dropdown list. If no ID is provided, 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 dropdown list 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 dropdown list. This is optional.Hint | string | undefinedundefined
isEmptyStartOptionis-empty-start-optionThis prop is used to determine whether or not the initial option displayed is empty. If set to true, it will render the default “select” text. If set to a string, it will render the string value.boolean | string | undefinedfalse
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 for the dropdown list. The name value is used to reference form data after a form is submitted.stringundefined
optionsoptionsThe options for dropdown list. Each option will be passed in through an object in the options array. This can either be passed in as an object directly (if using react), or as a string in HTML. In the example below, the options are being passed in as a string and there are three dropdown options displayed.DropdownOption[] | stringundefined
requiredrequiredThis is used to determine whether the dropdown list 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 currently selected dropdown value. The component keeps the host value in sync as users interact with the dropdown. If value is provided, it takes precedence over any selected flags passed through options.string | undefinedundefined

Events

EventDescriptionType
dropdownOnBlurEmitted when a keyboard input event occurs when a dropdown list has lost focus.CustomEvent<InputInteractionEvent & { focused: boolean; }>
dropdownOnChangeEmitted when a keyboard input or mouse event occurs when a dropdown list has been changed.CustomEvent<{ id?: string | undefined; value?: string | undefined; }>
dropdownOnFocusEmitted when a keyboard input event occurs when a dropdown list has gained focus.CustomEvent<InputInteractionEvent & { focused: boolean; }>
inputErrorOccurredEmitted when an error message is reported to the component.CustomEvent<{ errorMessage: string; }>

Dependencies

Depends on

Graph


Built with StencilJS