1. 53
  1.  

  2. 10

    There’s still one problem with SPAs in particular that doesn’t have a good solution: There’s no standard way to indicate to a screen reader that a new pseudo-page has loaded. An app can work around this with a hidden ARIA live region, but that doesn’t allow a screen reader to provide a standardized user experience whenever a new page loads, whether it was a real browser page load or not, and it also doesn’t allow the screen reader to do something smart like automatically read the content of the new page.

    To see (or rather, hear) this in action with Pinafore, go to the Pinafore home page in a browser that’s not already logged in, and activate the “Log in” link. The screen reader says nothing.

    I think the best solution to this would be a new DOM event that the SPA can fire. The browser should then translate that into the appropriate event in the host platform’s accessibility API.

    1. 1

      Thanks for the feedback! I agree that, absent any better solution, there should be a DOM event to announce page changes in SPAs. What’s a bit odd to me, though, is that screen readers don’t already do this when the URL changes? Maybe the History API is just not a reliable enough signal for an SPA page change.

      1. 2

        I tried that solution at my previous job, where I developed a Windows screen reader. It’s better than nothing, but not perfect. A couple of problems:

        • If the URL changes before the SPA finishes loading and rendering the new page, the screen reader may start reading too soon. I experienced this sometimes on Medium.
        • Some applications change the URL without doing the equivalent of a page load. Discourse’s implementation of infinite scroll is one example.

        Furthermore, no other screen reader is watching for the URL to change, and the one that I developed at my previous job is hardly a market leader (which is partly why I no longer work there). Not naming names because I don’t want this comment to show up in searches, or search engine alerts, for that company or product.

    2. 5

      The author’s project Pinafore (https://pinafore.social) is head-and-shoulders above nearly every other SPA I’ve ever used; it’s fast and responsive on 10-year-old hardware and very keyboard-friendly.

      1. 5

        It’s built with Svelte / Sapper (and also by a highly-skilled engineer!) which sees the modern trend of virtual DOM-diffing (eg React) as “pure overhead” - to quote Svelte’s creator.

        I made a little test app with Sapper and apart from some difficulty with transition animations (which big +1 for being built in and integrated with state changes!) I was pretty impressed. I think they’re doing a lot of things right, particularly in providing a cohesive out-of-the-box framework rather than leaving you to cobble bits together like with React.

        And it’s fast, there’s no doubt about it. The kind of things most websites are doing should be fast, even on 10-year-old-hardware. Especially as 10 year old hardware can include a quad-core core i5 at 2.67 ghz - or something even better.

        1. 2

          Yeah, the Pinafore author has literally spent years employed on the performance team of a major web browser, so he really knows his stuff. But even he has repeatedly pointed out that making an SPA that works properly is an enormous amount of work, even for someone who’s much more knowledgeable than the average web dev.

          1. 3

            making an SPA that works properly is an enormous amount of work, even for someone who’s much more knowledgeable than the average web dev.

            Yeah this is definitely true. It’s part of the appeal of React’s way of doing things, I think: Don’t think about how it is now, just try to figure out how it should look next, and I (React) will work out how to get there. But even that mental simplification still leaves a world of other things to know/care about if you’re trying to do it right (and comes with it’s own tradeoffs). Unfortunately accessibility often falls way down that list.

      2. 3
        <button type="button" aria-pressed="false">
         Unpressed
        </button>
        <button type="button" aria-pressed="true">
         Pressed
        </button>
        

        Incidentally, this makes it easier to write integration tests (e.g. using TestCafe or Cypress). Why rely on classes and styles, which might change if you redesign your app, when you can instead rely on the semantic attributes, which are guaranteed to stay the same?

        Cypress encourages the use of data- attributes to solve the problem of targeting changing classes and styles [0]. I like the idea of reusing accessibility attributes, but I think there’s probably an argument for keeping attributes-for-testing and attributes-for-accessibility as separate things.

        Overall I enjoyed this article, lots of interesting info in there.

        [0] Offtopic: this is a problem we’re having with Pendo, too: our Product team wants our classes to stay stable and predictable so that people who don’t understand CSS selectors in particular, and our code in general, can still use the tool. I can’t see it working out - these are internal values that shouldn’t be hooked into by a third-party system, and even less so by people who don’t understand what they’re doing. I forsee a data-pendo-create-user attribute in our future, even though it totally undermines the “you don’t need an engineer to start tracking an event in your app!” selling point of Pendo.

        1. 2
          <button type="button" aria-pressed="false">
            Unpressed
          </button>
          <button type="button" aria-pressed="true">
            Pressed
          </button>
          

          I didn’t know about the ARIA attributes, compare MDN.

          But what’s the advantage of encoding a toggle button like this instead of as an <input type="checkbox">?

          1. 2

            I don’t know of any hard-and-fast rules around this, but I think they just have slightly different semantics, same as the visual representation of a checkbox compared to a toggle. The Aria Practices document describes a mute button as a good example of a toggle button: http://w3c.github.io/aria-practices/#button

            Incidentally there is also a proposal for a “switch” element, which would have its own slightly different semantics: https://github.com/tkent-google/std-switch/blob/master/README.md

            1. 2

              https://lobste.rs/s/yvs2xp/don_t_use_checkboxes_2007 pretty much answers why the author (and I) recommend not using checkboxes.

              Though, most of the time, you’d probably be better off with radio buttons or a <select> menu.

              1. 1

                Hmm, but don’t those arguments apply equally to toggle buttons? I don’t see a fundamental difference between toggle buttons and checkboxes.

            2. 2

              Thanks a lot! I always knew the 100% accessibility score in Lighthouse is just a nice complement from Google