# Dropdowns and fields that change the page on their own

Source: https://easeweb.dev/learn/context-changes
Topics: Keyboard and focus > Focusing or changing a field does not change the page (WCAG 3.2.1, 3.2.2)
The fix: Make the change happen when people ask for it. Either add a button that applies the choice or opens the calendar, or make the change in place: re-sort the list, or show the calendar, while focus stays where it is. Nothing that happens on focus may move focus, open a window or leave the page.
Test with: keyboard, screen reader, zoom
References: https://www.w3.org/WAI/WCAG22/Understanding/on-focus.html https://www.w3.org/WAI/WCAG22/Understanding/on-input.html https://www.w3.org/WAI/WCAG22/Techniques/general/G80 https://www.w3.org/WAI/WCAG22/Techniques/general/G13 https://www.w3.org/WAI/WCAG22/Techniques/failures/F36 https://www.w3.org/WAI/WCAG22/Techniques/failures/F55

This is a recreated teaching example, not a finding about a named client. The code is a starting pattern: test it in your own product. No completed assistive-technology test is claimed here.

## What happens

A stationery shop lists its pens under a "Sort by" menu. Someone using a keyboard tabs to the menu and presses the down arrow to see what the other orders are. On Windows, the arrow changes a closed select's value straight away, and most browsers fire `change` at once, so the page reloads in the second order. Focus goes back to the top of the page. To try the third order, the person has to tab all the way down again, and every arrow press sends them back up.

The same shop's checkout has a delivery date field with a calendar. As soon as the field receives focus, the calendar opens and its script moves focus to the first day. Nobody can type a date, and pressing Shift+Tab to go back lands on the field again, which throws focus forward into the calendar once more.

## Why it fails

WCAG calls these changes of context: a new page, a new window, focus moved somewhere else, or content rearranged so much that the page means something else. Success Criterion 3.2.2 On Input says changing a control's value must not cause one unless people were told beforehand. Success Criterion 3.2.1 On Focus is stricter: receiving focus must never cause one, and it has no exception. The sort menu reloads the page on input, and the date field moves focus on focus.

## Who is affected

Mouse users rarely notice, because a mouse opens the list and picks one option with one click. The problem belongs to everyone who moves through a page a step at a time.

## What automation and AI miss

The markup is valid and every control has a label, so axe and similar scanners report nothing. The failure lives in a script that runs on `focus` or `change`, and only shows when someone presses the keys. A scan that clicks the select with a mouse picks one option and sees the reload as intended. AI tools asked to "make the select update the page" tend to write exactly the `onchange` handler shown below.

## Before: a sort menu that reloads on change

```html
<form action="/pens" method="get">
  <label for="sort">Sort by</label>
  <select id="sort" name="sort" onchange="this.form.submit()">
    <option value="popular">Most popular</option>
    <option value="name">Name, A to Z</option>
    <option value="new">Newest</option>
  </select>
</form>
```

Every new value submits the form, and a keyboard makes a new value at each arrow press. The reload puts focus back at the top of the page.

## Before: a date field that pulls focus into its calendar

```html
<label for="date">Delivery date</label>
<input id="date" name="date" onfocus="openCalendar()">

<script>
  function openCalendar() {
    calendar.hidden = false;
    calendar.querySelector('button').focus();
  }
</script>
```

Focus arrives on the field and is moved away before anyone can type. Arriving from either direction triggers it again.

## After: a button that applies the choice

```html
<form action="/pens" method="get">
  <label for="sort">Sort by</label>
  <select id="sort" name="sort">
    <option value="popular">Most popular</option>
    <option value="name">Name, A to Z</option>
    <option value="new">Newest</option>
  </select>
  <button type="submit">Sort</button>
</form>

<label for="date">Delivery date</label>
<p id="date-format">For example, 2026-12-14</p>
<input id="date" name="date" aria-describedby="date-format">
<button type="button" id="date-button"
  aria-expanded="false" aria-controls="calendar">Choose date</button>
```

The select and the field do nothing by themselves. The page reloads when someone presses Sort, and the calendar opens, taking focus, when someone presses Choose date: both are changes people asked for. The field also accepts a typed date, so the calendar is a help, not the only way in. Choosing a day fills the field, and choosing a day or pressing Escape closes the calendar and returns focus to Choose date.

## After: a change made in place, with focus left where it is

```html
<label for="sort">Sort by</label>
<select id="sort">…</select>
<p id="sort-status" role="status"></p>
<ul id="pens">…</ul>

<script>
  sort.addEventListener('change', () => {
    renderPens(sort.value);   // re-order the list; focus stays on the select
    sortStatus.textContent = `Sorted by ${sort.selectedOptions[0].text}.`;
  });

  date.addEventListener('focus', () => {
    calendar.hidden = false;  // show it; never call focus() here
  });
</script>
```

Re-ordering the list below the menu changes content, not context: the person is still on the same page, on the same control, and each arrow press simply shows the next order. The status line next to the menu tells screen reader users what happened. The calendar appears under the date field while focus stays in the field, so typing still works and Tab moves on into the calendar's days. This holds only while nothing else moves: the script must not scroll the page, move focus or replace the select, and the calendar must close with Escape and not cover the field below it.

## Which option to use

Both pass both criteria. The button is the smallest change, works without JavaScript, and suits any choice that has to load a new page, such as a category or a region; it costs one more Tab stop and a press. The change in place saves that press and feels quicker, but it needs script that re-renders without moving focus or scrolling, and a status message. Use the button when the choice leads to another page, and the change in place when the page can apply the choice itself.

## Implementation decisions

Telling people beforehand ("Choosing an order reloads the page") makes the sort menu pass 3.2.2, but it does not help the date field, because 3.2.1 has no such exception. It also leaves keyboard users sent away by the first option they pass, so treat it as a last resort for a control you cannot change.

Some patterns are not changes of context, and need no button:

- A tooltip or hint shown on focus: it adds content next to the control and leaves focus alone.
- A section shown when a checkbox is ticked, such as a separate billing address: content appears after the control, and focus stays on it.
- A list filtered as someone types in a search field: the page stays, and focus stays in the field.

Keep auto-advance out of split fields too. Moving focus to the next box once a box is full is a change of context on input, and it surprises people who check what they typed or correct a digit. A single field for the whole value avoids the problem.

If a component library opens its date picker on focus, look for an option to open it from a button instead, or wrap it so the field keeps focus. A month-sized calendar should be a single Tab stop with arrow keys inside it, as in the APG date picker dialog, rather than thirty Tab stops.

## Verify the fix

1. Put the mouse aside and press Tab, then Shift+Tab, through the whole form. Focus stops on every field in turn, in both directions, and the page never changes on its own.
2. Focus each select and press the up and down arrows without opening it. The address, the window and the focus stay where they are until you press the button, or the change appears in place with focus still on the select.
3. Open the calendar and press Escape. It closes, and focus is on the field or the button you came from.
4. With a screen reader, step through the options. Either the button is the next thing you reach, or the new order is announced while you stay on the select.
5. Search the scripts for `focus`, `focusin`, `change` and `input` handlers that call `submit()`, set `location`, call `window.open` or call `focus()` on another element.

Record the OS, browser and assistive-technology versions, the build, the date, and the actual result of each step. Repeat after the shared form or filter components change.

## Limits

This is a starting pattern, not a guarantee for every application. Browsers differ in when they fire `change` from the keyboard: on macOS the arrow keys open the list, and the value changes when it is confirmed. Test with the platforms your users have, and with the components your site really uses.
