Applying Web Accessibility in an Editor

#Editor#Web Accessibility#HTML

From the basics of general web accessibility to the accessibility points that change in an editor

In a recent interview, I was asked about the difference between the a tag and onclick. At the time, I only thought about the answer in terms of event handling or from a DOM perspective. But after the interview, when I thought about it again, that question wasn't simply about "what is technically different" — it was also a question that could be viewed from the perspective of what difference it makes for the user, namely the web accessibility perspective.

For example, if the goal is navigation, a href is more natural than div onclick.

  • <a href="..."> is recognized as a link by browsers and assistive technologies.
  • It can be focused with Tab and activated with Enter.
  • The default link behavior that the browser provides comes along with it as well. Things like opening in a new tab, copying the link, or integrating with browsing history.
  • On the other hand, div onclick can handle clicks, but it doesn't automatically get this default behavior and meaning.

There are more similar cases.

  • Using div onClick instead of button
  • Building an input UI with only contenteditable instead of input
  • Building the entire screen with only divs instead of semantic tags

I myself ran into these points often while developing a web-based editor. Editors in particular have far more interactions than typical pages, rely heavily on keyboard usage, and need to communicate the current position and state with more precision. So even though we're talking about the same web accessibility, accessibility on a general web page and accessibility in an editor have slightly different textures.

In this post, I'll first briefly summarize general web accessibility, and then write about how web accessibility in an editor — based on my experience — was different.


Web accessibility basics

Before talking about editors, let me first go over the basic elements you commonly encounter in general web accessibility.

Semantic HTML solves more than you'd think

When talking about web accessibility, it's easy to think of ARIA first, but in practice, using the right HTML element comes first.

For example:

  • If the goal is navigation, use a
  • If the goal is executing an action, use button
  • For input, use input, textarea
  • For lists, use ul, ol, li
  • For headings, use h1~h6

When you use the right tag, browsers and screen readers understand the role of that element better. Keyboard focus, default behavior, and exposure in the accessibility tree mostly come along for the ride.

<a href="/docs">View document</a>
<button type="button">Save</button>
<textarea aria-label="Document content"></textarea>

Conversely, if you try to solve everything with a single div, you can attach a click, but meaning isn't automatically created.

<div onclick="save()">Save</div>

In this case, even though it looks like a button visually, it's just a div from the perspective of assistive technology. In the end, the developer has to take care of role, tabindex, keyboard events, and state communication on their own.


Landmarks and structure change the navigation experience

Screen reader users don't "scan with their eyes" — they navigate based on structure. So dividing up the major sections of a page also matters.

<header>Header</header>
<nav aria-label="Main menu">...</nav>
<main>Main content</main>
<footer>Footer</footer>

Actually, in cases like this, you don't need to attach role="banner", role="navigation", and role="main" one by one. The HTML itself already carries the semantics. If anything, it feels more natural to use native semantics first and only use ARIA to fill in what's missing.


It must be usable with the keyboard alone

One thing that comes up often in web accessibility is keyboard accessibility. This isn't simply a matter of "are there shortcuts?" — it's closer to can you reach and execute the functionality without a mouse?

At minimum, the following needs to be satisfied.

  • Focus must be movable with Tab.
  • It must respond appropriately to Enter or Space.
  • It must be visually clear where the current focus is.

For a button, for example, the browser provides this behavior by default.

<button type="button">Close</button>

But if you use a div like a button, you don't get this default behavior.

<div
  role="button"
  tabindex="0"
  onclick="closeDialog()"
  onkeydown="if(event.key === 'Enter' || event.key === ' ') closeDialog()"
>
  Close
</div>

You can patch it like this, but the developer ends up having to reimplement everything the button would have done. So I often felt that web accessibility is closer to "making fewer forced workarounds" than "implementing more."


Screen readers don't automatically catch every screen change

In modern web apps where the screen changes dynamically, changes that are visually obvious are often not conveyed to screen reader users at all.

For example:

  • When saving is complete
  • When filter results change
  • When a modal opens
  • When an error message is added

In these cases, you can use attributes like aria-live to announce the change.

<div aria-live="polite" aria-atomic="true">Saved successfully.</div>
  • aria-live="polite": Reads at an appropriate time without interrupting what's currently being read.
  • aria-live="assertive": Cuts off what's currently being read and conveys the message immediately.
  • aria-atomic="true": Useful when you want the entire sentence read out, not just the changed part.

Also, buttons that have only an icon and no text need to have a name provided separately.

<button aria-label="Close">×</button>

Automated audit tools are a starting point, not the answer

When auditing accessibility, the following tools are commonly used.

  • Lighthouse
  • WAVE
  • axe DevTools

These tools are helpful for quickly finding missing attributes or obvious issues. However, real accessibility doesn't end with automated audits. In particular, things like focus movement, keyboard flow, how sentences sound on a screen reader, and dynamic state changes are easy to miss unless you actually try them yourself.


What changes when applying web accessibility in an editor

Everything up to this point is accessibility you commonly encounter on general web pages. But editors take it one step further in complexity.

That's because an editor isn't just a screen that displays information — it's an interaction-centric UI where the user writes, selects, moves around, and edits.

In the environment I worked in, there were considerations that differed from those of general pages.

Editors need to communicate "where you currently are" more clearly

On a general page, you can grasp your current location roughly from the page title or section structure. But editors are different.

The user needs information like:

  • Which paragraph they're currently in
  • Which text they're selecting
  • What formatting is applied
  • Whether they're inside a table
  • Whether focus is on the ribbon/toolbar or in the body

In other words, in an editor, beyond just "this button is the save button," it's important to communicate what the current document context is.

For example, you might need a live region like this.

<div aria-live="polite" aria-atomic="true" class="sr-only">
  Currently in paragraph 3.
</div>

Or, when formatting changes, an announcement like this might exist.

<div aria-live="polite" class="sr-only">Bold applied.</div>

Focus management becomes much more important

On the general web, things mostly work as long as the Tab order isn't drastically off. But in editors, focus has many places to travel between — the body, toolbar, dialogs, side panels, context menus.

So just "press Tab to go to the next element" isn't enough.

What was needed was things like:

  • Trapping focus inside a dialog when it opens
  • Restoring focus to the previous position when the dialog closes
  • Reflecting dynamically created buttons or panels in the focus order
  • Making movement between the toolbar and the editing area feel natural

For a modal, for example, a focus trap is needed.

<div role="dialog" aria-modal="true" aria-labelledby="dialog-title">
  <h2 id="dialog-title">Font settings</h2>
  <button>OK</button>
  <button>Cancel</button>
</div>

What matters here isn't just attaching role="dialog" — it's actually controlling Tab so it doesn't escape outside, and returning focus to where the user was working when the dialog closes.


Shortcuts become a core usage method, not a convenience feature

On general pages, keyboard accessibility often ends at Tab, Enter, and Space. But editors are different. The keyboard becomes the primary input device, not just an auxiliary one.

For example, there are shortcuts like these.

  • Ctrl+B, Ctrl+I, Ctrl+U: bold, italic, underline
  • Ctrl+L, Ctrl+E, Ctrl+R, Ctrl+J: alignment
  • Ctrl+Home, Ctrl+End: jump to start/end of the document
  • Shift + arrow keys: extend selection range
  • Cell movement inside a table
  • Navigation inside the toolbar/ribbon

Code that handles the bold shortcut, for example, might look like this.

function onKeyDown(event: KeyboardEvent) {
  if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === 'b') {
    event.preventDefault();
    toggleBold();
    announce('Bold applied.');
  }
}

But at an actual product level, there's more to consider beyond this.

  • Mac/Windows key differences
  • Overlap of input combinations
  • Conflicts with the IME
  • Whether you're in read-only mode
  • Whether there's a current selection range

In other words, in an editor, shortcuts aren't just a convenience feature — they're a fundamental interface that drives both accessibility and productivity at the same time.


The ribbon, toolbar, and panels are also interaction areas

In an editor, the body isn't the only thing that matters. Ribbon UIs, where formatting buttons, tabs, groups, dropdowns, and toggle buttons cluster together, also need to be designed well from an accessibility perspective.

In these areas, what mattered was:

  • Communicating that it's a toolbar
  • Communicating the selected state of tabs
  • Communicating the on/off state of toggle buttons
  • Letting the user navigate it in order via the keyboard

For example, a structure like the following is possible.

<div role="toolbar" aria-label="Formatting toolbar">
  <button aria-pressed="true">Bold</button>
  <button aria-pressed="false">Italic</button>
  <button aria-pressed="false">Underline</button>
</div>

For a tab UI, you need to communicate the current selection state.

<div role="tablist" aria-label="Ribbon tabs">
  <button role="tab" aria-selected="true">Home</button>
  <button role="tab" aria-selected="false">Insert</button>
  <button role="tab" aria-selected="false">View</button>
</div>

You don't have to read out everything that's visible

Editors have many elements that only carry meaning visually.

For example:

  • Rulers
  • Decorative guides
  • Print-preview overlays
  • Visual guide lines
  • Bubbles that only appear on screen while the actual content lives elsewhere

If you expose these as-is in the accessibility tree, it becomes a hindrance instead. So sometimes, hiding what should be hidden mattered more than "making things visible."

<div aria-hidden="true" class="ruler"></div>

Accessibility isn't the work of making everything readable — it's also the work of leaving only the information that's truly needed and tidying up the rest.


Wrapping up

When I heard the question about the difference between the a tag and onclick in the interview, I initially only thought of the technical differences. But thinking about it again, the question ultimately included the meaning the browser understands, the experience the user actually gets, and even the information assistive technology can interpret.

And what I felt while developing the editor was similar.

On the general web, you can solve many problems just by doing semantic tags, keyboard access, and screen reader support well. But editors need to go further.

  • You have to communicate the current editing context
  • You have to manage a complex focus flow
  • You have to provide a variety of shortcuts and states consistently
  • You have to distinguish visual elements from elements that carry actual meaning when exposing them

In the end, web accessibility in editors lies on the extension of general web accessibility, while being a slightly more interaction-centric, slightly more state-centric, and slightly more delicate problem.

While putting this together, I also got to look back on implementations I'd done before from a different angle. Going forward, when I build features, I want to keep looking beyond "does it work?" all the way to who can use it and how.