Skip to content

IJPL-175712 Accessibility UI guidelines #1505

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ijs.tree
Original file line number Diff line number Diff line change
Expand Up @@ -525,7 +525,7 @@
<toc-element toc-title="Tree"/> <!--TODO-->
</toc-element>
<toc-element topic="Principles.md">
<toc-element toc-title="Accessibility"/> <!--TODO-->
<toc-element topic="accessibility.md"/>
<toc-element toc-title="Dangerous Actions"/> <!--TODO-->
<toc-element topic="data_formats.md"/>
<toc-element toc-title="Default Values"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,5 @@ These issues are usually invisible in the UI, but they can still prevent users w
For each problem, the affected value in the Properties table contains a description that explains what it affects and how to fix it.

![Accessibility Checks](internal_ui_inspector_accessibility_checks.png)

> Refer to the [accessibility guidelines](accessibility.md) to learn more about accessibility best practices.
1 change: 1 addition & 0 deletions topics/ui/Principles.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Principles

- [](accessibility.md)
- [](data_formats.md)
- [](icons_style.md)
- [](layout.md)
Expand Down
342 changes: 342 additions & 0 deletions topics/ui/principles/accessibility.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,342 @@
<!-- Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -->

# Accessibility

Copy link
Collaborator

Choose a reason for hiding this comment

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

Since the article is mainly focused on iplementation details, maybe it makes sense to move it for example to the Base Platform section?

Copy link
Member Author

Choose a reason for hiding this comment

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

Good idea. I think I can extract the Assistive technology support section into an article here: https://plugins.jetbrains.com/docs/intellij/user-interface-components.html. And we can keep things about keyboard accessibility in UI guidelines and also later add the information about colors here. Both articles will have links to each other. What do you think?

<link-summary>Making the UI accessible to more people.</link-summary>

Accessibility means building interfaces that everyone can use, regardless of their abilities.
It allows people with different needs, such as those who rely on assistive technologies or need keyboard-only navigation, to fully interact with the product.
Follow these guidelines, based on [industry standards](https://www.w3.org/TR/WCAG22/), to ensure the UI is accessible for all.

## Keyboard accessibility

All functionality must be operable by using only the keyboard.
People who have trouble using a mouse, including those who are blind, have low vision, or have motor disabilities, rely on keyboard navigation to effectively use the interface.

### Focus basics

The basic way to interact with the UI by using the keyboard is to switch focus between components with <shortcut>Tab</shortcut> and <shortcut>Shift+Tab</shortcut>.
For some components, such as lists, drop-down menus, or tables, arrow keys can also be used to navigate between items.
Once a component is focused, it can be activated by pressing <shortcut>Space</shortcut>.
Copy link
Collaborator

Choose a reason for hiding this comment

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

also add info on how focused components should look like (e.g. get highlighted with the blue stroke)

Copy link
Member Author

Choose a reason for hiding this comment

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

I can now add some basic info (1-2 sentences) that focused components need to have a focus indicator. And then later you can expand it with an illustration and add more info if needed. I wrote about this part here: UX-3531. Does that sound good?


Make all interactive elements focusable to achieve [full keyboard operability](https://www.w3.org/WAI/WCAG22/Understanding/keyboard.html).
This includes buttons, checkboxes, text fields, lists, tables, dropdowns, and other controls that users can interact with.

Non-interactive components, such as labels and panels, should not be focusable.
However, in some cases, they can be focusable to let screen reader users access important information.
Use [`ScreenReader.isActive()`](%gh-ic%/platform/util/ui/src/com/intellij/util/ui/accessibility/ScreenReader.java) to adjust the behavior only for screen reader users.

### Keyboard traps

Make the UI traversable in a cycle without trapping the keyboard focus.
A [keyboard focus trap](https://www.w3.org/WAI/WCAG22/Understanding/no-keyboard-trap.html) occurs when a user cannot navigate away from a component by using the standard keyboard navigation.
This prevents them from accessing other parts of the interface.

Ensure that a user can always navigate away from any focusable component by using <shortcut>Tab</shortcut>, <shortcut>Shift+Tab</shortcut>, or <shortcut>Escape</shortcut>.
For instance, continuously pressing <shortcut>Tab</shortcut> or <shortcut>Shift+Tab</shortcut> in a dialog should result in cycling through all components and returning to the starting point.
To break out of such focus loops, use <shortcut>Escape</shortcut> to close dialogs and popups, or move focus back from a tool window to the editor.

### Managing focus

When new content appears, such as popups, modal dialogs, or dynamic content, ensure that:

* Focus is moved to the new content, or there is a way to reach it by using only the keyboard.
* Focus is not moved unexpectedly when users are interacting with components like lists or dropdowns to avoid a [change of context](https://www.w3.org/WAI/WCAG22/Understanding/on-focus.html#dfn-changes-of-context).

## Assistive technology support

Assistive technologies, such as screen readers and voice control, rely on accessibility metadata provided by UI components.
For example, a checkbox might be announced by screen readers as "Don't ask again, checkbox, not checked, Alt+D".
Voice control users can say "Press Don't ask again" to activate the checkbox.
This integration is enabled by properly defined accessible metadata.

Follow these guidelines to ensure that users of assistive technology can fully interact with the UI.

### Accessible properties

Each UI component has an associated [`javax.accessibility.AccessibleContext`](https://docs.oracle.com/en/java/javase/21/docs/api/java.desktop/javax/accessibility/AccessibleContext.html) object that defines properties for assistive technologies.
The accessible context can also implement [`Accessible*`](https://docs.oracle.com/en/java/javase/21/docs/api/java.desktop/javax/accessibility/package-summary.html#class-summary) interfaces to provide additional metadata or ways for assistive technologies to interact with the component.

> For [common UI components](Components.topic), basic accessibility support is often already implemented.
> But when creating custom components or extending existing ones, you may need to extend the accessible context or modify its properties.
>
{style="note"}

Example of customizing the accessible context and its properties:
<tabs group="languages">
<tab title="Kotlin" group-key="kotlin">

```kotlin
class ActionLink : JButton() {
override fun getAccessibleContext(): AccessibleContext {
if (accessibleContext == null) {
accessibleContext = object : AccessibleAbstractButton() {
override fun getAccessibleRole() = AccessibleRole.HYPERLINK
override fun getAccessibleValue() = null
}
}
return accessibleContext
}
}

val link = ActionLink()
link.accessibleContext.accessibleName = "Open in browser"
```

</tab>
<tab title="Java" group-key="java">

```java
class ActionLink extends JButton {
@Override
public AccessibleContext getAccessibleContext() {
if (accessibleContext == null) {
accessibleContext = new AccessibleAbstractButton() {
@Override
public AccessibleRole getAccessibleRole() {
return AccessibleRole.HYPERLINK;
}

@Override
public AccessibleValue getAccessibleValue() {
return null;
}
};
}
return accessibleContext;
}
}

ActionLink link = new ActionLink();
link.getAccessibleContext().setAccessibleName("Open in browser");
```

</tab>
</tabs>

#### Accessible name and description

An [accessible name](https://docs.oracle.com/en/java/javase/21/docs/api/java.desktop/javax/accessibility/AccessibleContext.html#getAccessibleName()) is the label that defines the component's purpose for assistive technology users.
Set a clear and descriptive accessible name for all focusable components.

For example, a simple button with text should have that text as its accessible name.
For a text field with a label in front of it, the accessible name should be the label's text.
A list without a visible title should still have an accessible name that describes its content.

In many cases, the accessible name is already taken implicitly from the following sources:

* The text property of components such as labels or buttons.
* Tooltip text.
* The label of the component that was set by `JLabel.setLabelFor()`.

If the name was not applied implicitly, set it by calling `AccessibleContext.setAccessibleName()` or by overriding `AccessibleContext.getAccessibleName()`:

<tabs group="languages">
<tab title="Kotlin" group-key="kotlin">

```kotlin
class AccessibleCheckBox : AccessibleJLabel() {
override fun getAccessibleName() = myLabel.text
}

checkBox.accessibleContext.accessibleName = "Don't ask again"
```

</tab>
<tab title="Java" group-key="java">

```java
class AccessibleCheckBox extends AccessibleJLabel {
@Override
public String getAccessibleName() {
return myLabel.getText();
}
}

checkBox.getAccessibleContext().setAccessibleName("Don't ask again");
```

</tab>
</tabs>

Tips for choosing an accessible name:

* Don't include the component's role in the accessible name.
For example, for a password text field, set the name as "Password" instead of "Password text field."
* For complex components, include all visible information in the accessible name.
For example, for a panel that consists of a title, subtitle, and icon, combine all these parts in the accessible name.

An accessible description provides additional context, such as instructions, keyboard shortcuts, placeholders, or explanatory text.
Use it for supplementary information that helps users understand how to interact with the component.

The accessible description is set similarly to the accessible name, either by calling `AccessibleContext.setAccessibleDescription()` or by overriding `AccessibleContext.getAccessibleDescription()`.

#### Accessible role

The accessible role tells assistive technologies what type of component they are interacting with.
Use the [`AccessibleRole`](https://docs.oracle.com/en/java/javase/21/docs/api/java.desktop/javax/accessibility/AccessibleRole.html) value that correctly represents the component's function.

The accessible role can be changed by overriding `AccessibleContext.getAccessibleRole()`:

<tabs group="languages">
<tab title="Kotlin" group-key="kotlin">

```kotlin
class AccessibleCheckBox : AccessibleJLabel() {
override fun getAccessibleRole() = AccessibleRole.CHECK_BOX
}
```

</tab>
<tab title="Java" group-key="java">

```java
class AccessibleCheckBox extends AccessibleJLabel {
@Override
public AccessibleRole getAccessibleRole() {
return AccessibleRole.CHECK_BOX;
}
}
```

</tab>
</tabs>

Tips for customizing the role:

* Use `AccessibleRole.LABEL` for plain text content and `AccessibleRole.TEXT` for text fields and text areas that are editable or support selection.
* Set an appropriate button role: `AccessibleRole.PUSH_BUTTON`, `AccessibleRole.RADIO_BUTTON`, `AccessibleRole.TOGGLE_BUTTON`, or `AccessibleRole.HYPERLINK`.

#### Accessible state

The [accessible state](https://docs.oracle.com/en/java/javase/21/docs/api/java.desktop/javax/accessibility/AccessibleState.html) communicates the component's current condition to assistive technologies.
For example, it can tell screen reader users that the component is selected, expanded, or editable.

Adjust the component's state set by overriding `AccessibleContext.getAccessibleStateSet()`:

<tabs group="languages">
<tab title="Kotlin" group-key="kotlin">

```kotlin
class AccessibleCheckBox : AccessibleJLabel() {
override fun getAccessibleStateSet(): AccessibleStateSet {
val set = super.getAccessibleStateSet()
if (myChecked) {
set.add(AccessibleState.CHECKED)
}
return set
}
}
```

</tab>
<tab title="Java" group-key="java">

```java
class AccessibleCheckBox extends AccessibleJLabel {
@Override
public AccessibleStateSet getAccessibleStateSet() {
AccessibleStateSet set = super.getAccessibleStateSet();
if (myChecked) {
set.add(AccessibleState.CHECKED);
}
return set;
}
}
```

</tab>
</tabs>


Notify assistive technologies when the state changes:

<tabs group="languages">
<tab title="Kotlin" group-key="kotlin">

```kotlin
accessibleContext.firePropertyChange(
AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
null,
AccessibleState.CHECKED
)
```

</tab>
<tab title="Java" group-key="java">

```java
getAccessibleContext().firePropertyChange(
AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
null,
AccessibleState.CHECKED
);
```

</tab>
</tabs>

#### Accessible interfaces

Advanced accessibility features are provided through specialized interfaces, such as `AccessibleAction`, `AccessibleText`, `AccessibleSelection`, and `AccessibleValue`.
These are typically needed when implementing custom components from scratch.
Refer to the [list](https://docs.oracle.com/en/java/javase/21/docs/api/java.desktop/javax/accessibility/package-summary.html) of available interfaces to determine whether any need to be implemented.

> Look at similar Swing components to see which interfaces they implement. For example, when working on a new slider-like component, check the interfaces implemented by [`JSlider.AccessibleJSlider`](https://docs.oracle.com/en/java/javase/21/docs/api/java.desktop/javax/swing/JSlider.AccessibleJSlider.html).
>
{style="note"}

### Announcing live changes

Screen readers announce accessible property changes of the currently focused component automatically.
For example, when a user checks a checkbox, the screen reader announces the new state.
This happens through property change events fired by the component.

However, in some cases, users need to be notified of changes outside the focused component. Or the event that you want to notify about doesn't fit into existing property change support.

For these scenarios, use [`AccessibleAnnouncerUtil.announce()`](%gh-ic%/platform/util/ui/src/com/intellij/util/ui/accessibility/AccessibleAnnouncerUtil.java) to make screen readers announce a specific string.

<tabs group="languages">
<tab title="Kotlin" group-key="kotlin">

```kotlin
if (AccessibleAnnouncerUtil.isAnnouncingAvailable()) {
AccessibleAnnouncerUtil.announce(mySearchPanel, "No results found", true)
}
```

</tab>
<tab title="Java" group-key="java">

```java
if (AccessibleAnnouncerUtil.isAnnouncingAvailable()) {
AccessibleAnnouncerUtil.announce(mySearchPanel, "No results found", true);
}
```

</tab>
</tabs>

Common cases for using announcements:

* Error messages or validation results.
* Notifications or popups that are shown but don't receive keyboard focus.
* Background task completion.
* Search or filtering results.

## Tools

### Screen readers

The IntelliJ Platform supports NVDA and JAWS screen readers on Windows, and VoiceOver on macOS.
Test the UI with a screen reader to verify that all functionality is available and that the announced information is correct and complete.

> Learn more about screen reader functionality and commands from their official user guides:
> [NVDA](https://download.nvaccess.org/releases/2025.1.2/documentation/userGuide.html),
> [JAWS](https://support.freedomscientific.com/products/blindness/jawsdocumentation),
> and [VoiceOver](https://support.apple.com/guide/voiceover/welcome/mac).

### UI Inspector

Use the [UI Inspector](internal_ui_inspector.md) to examine accessible properties of UI components.
You can also perform an [accessibility audit](internal_ui_inspector.md#accessibility-checks) to check for common issues and get information on how to resolve them.