Accessibility and Sefaria

Noah Santacruz edited this page Jan 14, 2018 · 1 revision

The Problem

It’s relatively easy to make static web content accessible, so long as you use the right HTML tags, and include the proper alt and title tags to help assistive technology identify elements of the page that were are invisible. Using standard HTML web elements also allows for keyboard navigation to work more or less out of the box, and since early websites were essentially styled with a simple document structure to mirror the printed page, they remained relatively easy to navigate for all users.

But complex web applications require structures (e.g. interactive controls) that go beyond what regular HTML offers. We've crafted Sefaria using many divs and spans wrapped with lots of CSS and Javascript in order to get the site to "look" & function the way we might expect it to. However, doing so without paying attention to accessibility means that users who access the site using assistive technology are unable to access large swaths of the information and interactivity we offer.

An Example

Screen shot of Sefaria Source Sheet header

Original Code: <div id="save" class="button" onclick="...">...</div>

This example is visible and clickable to sighted-users, but is unselectable by users navigating via the keyboard, and is functionally invisible to a screen reader and other assistive technology which understands this to be identical to just regular text.

Better: <div id="save" class="button" tabindex="0" onkeyup="..." onclick="...">...</div>

This adds keyboard navigation to the element, but it's still functionally invisible to a screen reader.

Best: <div id="save" role="button" class="button" tabindex="0" onkeyup="..." onclick="...">...</div>

This adds the ARIA role attribute so that assistive technologies can now render it properly.

Another Best Alternative: <button id="save" class="button"> No JS required, however requires additional CSS hacking to get it to look the same cross-browser, and isn't always possible in all situations

A digression on ARIA

ARIA = Accessible Rich Internet Applications in short it helps assistive technology understand the role (what type of widget is this? (e.g. 'slider')), the state (what is its situation? (e.g. 'disabled')), and its identity (what does it represent? (e.g. 'volume control'))

This information is mapped by the browser to the operating system's accessibility API and exposed to assistive technologies. Which (ideally) will automatically announce widget-specific hints and prompts (e.g. JAWS "... button - to activate, press SPACE bar")

More details:

Suggestions/Best Practices

this is a work in progress

Use html elements other than <span> and <div> wherever possible

Old standby native HTML elements such as <button> <a> <h1> and newer semantic elements like <header> <footer> <section> <aside> etc. are better for SEO, and out of the box is more easily rendered by accessible technology than <div> and <span>. Most things will work immediately and without any additional work required (though it may require some additional attention on the CSS side to get the look and feel just right)

Every click or interaction that changes the url in the browser should be rendered as a link.

We now have component built in for this for react -- otherwise make sure to do it yourself do it yourself.


If you’re stuck with markup that you can’t change easily or really need to display it differently add the tags in. We’ve now tried to bake as many of these as possible into our existing React Components where we’ve already deployed them, and we will be deploying these as we move forward.

The general principle is to just tack on a role and and a specific aria-tag where appropriate. e.g.:

  • Headings -- if you can’t use h1-h6:

    • <p class="heading1" role="heading" aria-level="1">Fake Level Heading 1</p>
    • <p class="heading2" role="heading" aria-level="2">Fake Level Heading 2</p> Example
  • Toggle Button:

    • <span tabindex="0" role="button" aria-pressed="false" class="...">Option</span>
    • <span tabindex="0" role="button" aria-pressed="true" class="...">Option</span>
  • Radio Button:

    • <span tabindex="-1" role="radio" aria-checked="false" class="...">Yes</span>
    • <span tabindex="0" role="radio" aria-checked="true" class="... selected">No</span>
    • <span tabindex="-1" role="radio" aria-checked="false" class="...">Maybe</span> Example

Anything that you click that doesn't have text in it needs an aria-label attribute.

If the role and aria attributes and text of the element doesn't adequately explain what the element does or how it functions, use aria-label.

This ARIA attribute effectively tacks on whatever message you assign to it, to whatever element its associated with, and is automagically read immediately after the content is by the screen reader. If you need to give directions or a little more explanation to a user who uses assistive technology, this is the most effective way to do so, even if the rest of the markup isn’t perfect.

Some places we currently use this include:

Set the tabindex to 0 on all clickable elements that don't already have focus by default (e.g. <div> & <span>)

  • when these elements become disabled be sure to set the tabindex to -1

When a component becomes visible, you probably want to move the focus to that element.


Clickable elements also need to be triggered on keypress

Much of this will be done for you automatically if you're following the rules above, but otherwise you'll need to write your own keypress events to listen for code 13 (enter) and then trigger the click accordingly. We use a similar pattern to listen for the escape key to close panels in multipanel mode

Notes on modals, menus and other interactive elements we don't use regularly

These are often difficult to manage and require a whole host of other javascript trickery including:

Current state and known issues

We now believe that users who access Sefaria with the help of assistive technologies should now have a comparable experience throughout the site to those who do so without (excepting editing source sheets). At worst, users should be able to explain to us what is and isn’t working for them so that we can fix it.

We plan to continue to address these issues and build even richer accessible experiences going forward.

You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.