References

Beginner-friendly references for web development, with live, editable examples.

The HTML aria-orientation attribute

ARIA Accessibility
In short

The aria-orientation attribute states whether a widget is horizontal or vertical. Most roles that support it already have a default, so you mainly need it when a widget goes against that default, such as a vertical tablist or toolbar. It changes neither the layout nor the arrow keys.

Overview

The aria-orientation property declares a widget's direction as horizontal or vertical, or marks it as unknown or ambiguous. This can matter to users, because orientation affects what the left, right, up and down arrow keys are expected to do.

Its default depends on the role. A listbox, menu, scrollbar or tree defaults to vertical, and a menubar, separator, slider, tablist or toolbar defaults to horizontal.

Two usable roles have no default direction. A radiogroup stays undefined, because its expected orientation is ambiguous, and treegrid lists no default either. ARIA 1.1 made undefined the general default, replacing horizontal.

A toolbar with flex-direction: column is still exposed as horizontal, because layout set in CSS doesn't change the value. The arrow keys don't follow aria-orientation either, and changing how they behave requires JavaScript.

An <hr> takes the separator role's attributes, so aria-orientation="vertical" is valid there. A range input becomes vertical through the CSS writing-mode property, and aria-orientation alone leaves its layout unchanged.

Syntax

<div role="tablist" aria-label="Settings" aria-orientation="vertical">
  <button role="tab" aria-selected="true">Profile</button>
  <button role="tab" aria-selected="false">Billing</button>
</div>

Values

Value
horizontal | vertical | undefined

Example

Live example
<p style="margin:0 0 8px">On a keyboard, focus a toolbar button and press the arrow keys, then stack the toolbar and try them again.</p>
<label><input type="checkbox" id="stack"> Stack the toolbar vertically</label>
<div role="toolbar" id="bar" aria-label="Text formatting" style="display:flex;gap:6px;width:max-content;margin:8px 0">
  <button type="button">Bold</button>
  <button type="button" tabindex="-1">Italic</button>
  <button type="button" tabindex="-1">Underline</button>
</div>
<p role="status" id="state" style="margin:0">No aria-orientation is set, so the toolbar role's horizontal default applies.</p>
<script>
const bar = document.getElementById('bar');
const buttons = [...bar.querySelectorAll('button')];
const state = document.getElementById('state');
document.getElementById('stack').addEventListener('change', function () {
  if (this.checked) bar.setAttribute('aria-orientation', 'vertical');
  else bar.removeAttribute('aria-orientation');
  bar.style.flexDirection = this.checked ? 'column' : 'row';
  state.textContent = this.checked
    ? 'aria-orientation is vertical, and this script now moves focus with the Up and Down arrow keys.'
    : 'aria-orientation is removed, so the horizontal default returns, and this script moves focus with the Left and Right arrow keys.';
});
bar.addEventListener('focusin', function (event) {
  buttons.forEach(function (button) { button.tabIndex = button === event.target ? 0 : -1; });
});
bar.addEventListener('keydown', function (event) {
  const vertical = bar.getAttribute('aria-orientation') === 'vertical';
  const back = vertical ? 'ArrowUp' : 'ArrowLeft';
  const forward = vertical ? 'ArrowDown' : 'ArrowRight';
  const step = event.key === back ? -1 : event.key === forward ? 1 : 0;
  if (!step) return;
  event.preventDefault();
  const index = buttons.indexOf(document.activeElement);
  const next = buttons[(index + step + buttons.length) % buttons.length];
  next.focus();
  state.textContent = event.key + ' moved focus to ' + next.textContent + '.';
});
</script>

Best practices

  • Leave aria-orientation off a widget that matches its role's default. Add it when a widget doesn't have the default, expected orientation.
  • Change the value along with the layout, such as when a handler turns a tab list horizontal at narrow widths.
  • Swap the arrow keys along with the value. In a vertical tab list, the down arrow does what a right arrow normally would, and the up arrow does what a left arrow would.
  • Set a value on a radiogroup whose direction is fixed. Without the attribute, it has no direction to report.

Frequently asked questions

Does aria-orientation have a default value?
The aria-orientation value defaults to undefined, but many roles set their own default. A slider counts as horizontal and a listbox as vertical unless you say otherwise.
Do I need aria-orientation on a vertical tab list?
Yes, a vertical tablist needs aria-orientation set to vertical, because that role defaults to horizontal.
Does aria-orientation=undefined clear a role's default?
Under WAI-ARIA 1.2, aria-orientation=undefined replaces the role's default with an unknown orientation. Chrome and Firefox still expose horizontal for a toolbar with that value, so don't count on it to clear a default.
Will the arrow keys follow aria-orientation automatically?
No, key handling stays with your script even when aria-orientation is set. On a native range input, the Up arrow does the same thing with the attribute as without it.
What value does aria-orientation take on a vertical separator?
Each separator should have an aria-orientation value consistent with how it's drawn. On a vertical separator, that value is vertical, which overrides the role's horizontal default.