Skip to content

[6.x] Keep keyboard focus inside the licensing alert - #15673

Merged
jasonvarga merged 3 commits into
6.xfrom
15673-modal-focus-trap-behind-fullscreen-portals
Oct 20, 2026
Merged

jasonvarga merged 3 commits into
6.xfrom
15673-modal-focus-trap-behind-fullscreen-portals

Conversation

@jaygeorge

Copy link
Copy Markdown
Contributor

Description of the Problem

When the licensing alert shows on page load, keyboard focus can end up in a field behind the blurred backdrop rather than in the alert. On an entry with a Bard field, for example, the cursor sits in the Title field, so typing goes into the entry and Tab moves through the page behind.

Modals only trap focus while they're the topmost portal, and "topmost" meant the last portal created. Bard, Markdown, Replicator, Grid, Group, Table and the code editor all register a portal for their fullscreen mode as soon as they load, even when they aren't fullscreen. If those fields load after the alert opens, the alert stops being "topmost", its focus trap switches off, and the Title field's autofocus takes focus.

What this PR Does

Portals now know whether they're disabled, and portals.top() skips disabled ones. A disabled portal renders in place rather than on top of anything, so it shouldn't count. Modals use top() to decide whether to trap focus. A field that's actually in fullscreen still counts as on top, so focus stays inside it.

I went for this rather than special-casing the licensing alert or stopping the Title field autofocusing while a modal's open, as the cause is in how the top portal is worked out. Any modal that opens before those fields load would hit the same thing.

Stacks have the same "last portal created" check. I've left them alone here because changing it would start trapping focus in most entry-editing stacks, which deserves its own PR.

The new methods are portals.top(), portals.isDisabled(id), portals.setDisabled(id, bool) and portal.setDisabled(bool). They're all additions, and nothing existing changes.

How to Reproduce

  1. Get the licensing alert showing, e.g. enable Pro without a valid licence. If you've snoozed it, run localStorage.removeItem('statamic.snooze_license_banner') in the console.
  2. Open an entry whose blueprint has a Bard (or Markdown, Replicator, Grid, etc.) field.
  3. Before this PR, focus is in the Title field behind the alert. Pressing Tab moves through the page behind it.
  4. After this PR, focus is in the alert and Tab goes to Snooze.

@jasonvarga
jasonvarga merged commit e7d03d5 into 6.x Oct 20, 2026
65 checks passed
@jasonvarga
jasonvarga deleted the 15673-modal-focus-trap-behind-fullscreen-portals branch October 20, 2026 17:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants