Skip to content

Variables: Improve a11y#1404

Merged
idastambuk merged 10 commits intomainfrom
idastambuk/variable-a11y
Apr 2, 2026
Merged

Variables: Improve a11y#1404
idastambuk merged 10 commits intomainfrom
idastambuk/variable-a11y

Conversation

@idastambuk
Copy link
Copy Markdown
Contributor

@idastambuk idastambuk commented Mar 19, 2026

Right now, we're not announcing variable labels to screen readers. This PR:

  • exposes a util getVariableControlId function that gets the id for the variable that will match the htmlFor. This function is used in core grafana PR that completes this feature
  • passes inputId to select elements (react-select requires it to connect the internal input to htmlFor)
  • replaces some ids with the new getVariableControlId
  • for adhoc filters, I had to prevent opening on focus because it would take away the focus from the input. This would confuse the voice over utility and wouldn't announce to the user they're in the adhoc filter input.
  • the above still didn't solve the problem where, if there were filters added, the input would automatically focus on the first pull. To solve this I added an intermediate element that would be only read out with a voice over and that would announce the label. Thank you @mdvictor for the idea

To test:

  • checkout to this PR in main grafana
  • install the packages built from this PR
  • yarn dev
  • press CMD + Fn + F5 to open the voice over utility
  • add different types of variables and navigate through them with a keyboard. When landing on each variable, the voice over should read out its label

This is how it works after the fix, with the adjustment for ad hoc filters:

Screen.Recording.2026-03-20.at.15.29.12.mov

@idastambuk idastambuk requested a review from a team March 24, 2026 09:47
return result;
}

export const getVariableControlId = (variableType: VariableType, key?: string) => {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

have we considered making the control id a property on the variable/controller instead of a separate utility method?

right now every consumer needs to call getVariableControlId(type, key) with the right args, and on the grafana side (
#120758) the call sites are already a bit inconsistent (variable.state.key vs variable.id). Also key was added to AdHocFiltersController purely to feed into this function, feels like the controller could just expose the final controlId directly.

something like:

getControlId(): string {
  return getVariableControlId(this.state.type, this.state.key);
}
id={model.getControlId()}

WDYT?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added it to the adhoc controller here and removed the key prop, but I think adding it to all variable models (or introducing a base class just fort his api) might be a bit of an overkill for an accessibility change? 🤔

I agree the call sites are inconsistent, and looking at them again, the changes in OptionsPicker.tsx, PickerRenderer.tsx and TextBoxVariablePicker.tsx might not make sense since they're legacy non-scenes components, so they probably don't need to use scenes utils. I reverted those changes in a new commit it that PR. I tested with scenes disabled and the new changes and it works fine as well

}

const getKeyComboboxElement = () => getAllByRole(screen.getByTestId('AdHocFilter-'), 'combobox')[0];
const getAdHocInputElement = () => screen.getByPlaceholderText('Filter by label values');
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the new UI changes this placeholder to I think + label = value, I think that is why tests are failing

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed!

@idastambuk idastambuk requested a review from mdvictor April 1, 2026 11:01
Copy link
Copy Markdown
Collaborator

@mdvictor mdvictor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! I've mainly focused on the adhoc code changes, although it looks good overall. Tested the adhoc filters var and with a custom var

@idastambuk idastambuk merged commit aec335e into main Apr 2, 2026
14 checks passed
@idastambuk idastambuk deleted the idastambuk/variable-a11y branch April 2, 2026 12:19
@idastambuk idastambuk added release Create a release when this pr is merged patch Increment the patch version when merged labels Apr 2, 2026
@scenes-repo-bot-access-token
Copy link
Copy Markdown

🚀 PR was released in v7.3.5 🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

patch Increment the patch version when merged release Create a release when this pr is merged released type/accessibility

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants