A Month of Accessible Elm

bit.ly/elm-a11y

Hi, I'm Brooke!

Hi, I'm Brooke!

📕

This is the story of my foray into Accessibility in Elm.

But first... habits.

Big goals

journal with blank new years resolutions

2019: be healthy?

vegetables doing exercise

Top 10 Resolutions

1. Diet or eat healthier
2. Exercise more
3. Lose weight
4. Save more and spend less
5. Learn a new skill or hobby
6. Quit smoking
7. Read more
8. Find another job
9. Drink less alcohol
10. Spend more time with family and friends

Success Rates

60% make resolutions

8% keep them

Why aren't my resolutions effective?

 

  • 🤷‍♀️ Too ambiguous
  • ⏳ Too long-term

 

Big goals ➡️ approachable habits

confused dog
carrots for eating

➡️

Small habit #1

Lift weights twice a week for just one month 🏋️‍♀️

Hey... that wasn't so bad.

weights

👻 Big goals are scary.

 

🐻 Little habits are approachable.

Okay, Brooke. That's not revolutionary.

"Better than Before" book cover
"Atomic Habits" book cover
S.M.A.R.T. goals marketing

Bring on the monthly habits!

Good habits are...

 

  • Purposeful
  • Specific
  • Time limited

 

Habit log

  1. ✅ January: Floss every night
  2. 🚫 February: Bike or walk to 80% of places in a 10 mile radius
  3. March: Take my vitamins daily

 

Overall, small habits worked!

Napoleon Dynamite's uncle being successful

Excellence

... another big goal

 

If we want our product to be excellent, our site should be accessible to a diverse range of students.

Web accessibility... what's that?

cute confused puppies

Accessibility... for whom?

For scale, there are 327 million people in the United States

Accessibility... for whom?

285 million people worldwide who are blind or visually impaired

Accessibility... for whom?

voiceover preferences screen

Accessibility... for whom?

275 million users who are deaf or hearing impaired

Accessibility... for whom?

Users with conditional disabilities

Accessibility... for whom?

Accessibility best practices benefit everyone.

I’m going to make the assumption that we all would like our applications to be accessible to all of these user groups, because we are an empathetic crew, and we care about our users.

🤗

 

 

 

 

What do we mean by "accessible"?

Web Content Accessibility Guidelines uses the acronym POUR

What do we mean by "accessible"?

  • Perceivable
  • Operable
  • Understandable
  • Robust

Perceivable

Examples:

  • Alt text for images
  • Content has sufficient contrast
  • Captions for multimedia

Operable

Examples:

  • Users can operate the app using a keyboard
  • Users have enough time to read and use the content

Understandable

Examples:

  • Text is readable
  • Users understand how to correct mistakes

Robust

Examples:

  • Content is robust across tools, including assistive technologies like screen readers

Why is accessibility difficult?

We agree our app should usable by a diverse range of users.

 

But... accessibility can feel like a daunting task.

 

 

 

 

Excellence in accessibility

man pressing alarm

Be very healthy

Excellence in accessibility

Maybe you've made an accessibility goal?

My usual reasons

  • 💬 I don’t know anything about accessibility!
  • 💬 I don’t know how to check for accessibility!
  • 💬 Adding accessibility takes too much time!

 

 

 

 

Maybe... I need a smaller goal.

Or... a tiny habit.

 

 

 

 

👩‍🚒 Tiny habits to the rescue!

Habits towards accessibility

 

🌳 Big Goal: Excellence in accessibility

 

Habits towards accessibility

 

 

🌱 Little Goal: I want to write UI tests based on interactions that would help someone using a screen reader navigate the page.

 

 

 

The month of accessible Elm!

woman holding a calendar

Goal: testing for accessibility

  • ✅ Purposeful
  • ✅ Specific
  • ✅ Time limited

🎉 TDD is an existing habit!

On to the project!

cat wearing glasses with text that says "i'm ready"

The project

One of the oldest pages on the site!

How do we verify this?

Best: verify with a screen reader user

How do we verify this?

Next best: verify myself with a screen reader, like Voice Over

How do we verify this?

Alright: let's just remove browser styling to see the most egregious errors

What will this reveal?

  • Non-interactive elements with event listeners
  • Places where we are using background images to convey content

What won't this reveal?

  • Images with no alt text
  • When we are using roles and widgets improperly

Okay, let's do this!

llama saying, "bring it on"

Selecting an interest

Selecting an interest

selecting interests, unstyled

(Unstyled)

Deselecting interests

Deselecting interests

deselecting interests, without styles

(Unstyled)

😱

 

Continuing onwards

Continuing onwards

interests page with all interests selected, unstyled

(Unstyled)

On to the Elm!

Setting up a test

Understandable: Test for clear instructions on the page

avh4/elm-program-test

Text

spec : Test
spec =
    test "instructs the user how to select interests" <|
        \_ ->
            ProgramTest.createDocument
                { init = Interests.init
                , view = Interests.view
                , update = Interests.update
                }
                |> ProgramTest.start testFlags
                |> ProgramTest.ensureViewHas
                    [ Selector.text "Select your interests."
                    ]
                |> ProgramTest.done

Adding to our test

Operable: add a test for selecting an interest

Past habit: selecting by class name

Text

spec : Test
spec =
    test "shows the interest page" <|
        \_ ->
            ProgramTest.createDocument
                { init = init
                , view = view
                , update = update
                }
                |> ProgramTest.start testFlags
                |> ProgramTest.simulateDomEvent
                    (Query.find
                        [ Selector.class "InterestButtonClass"
                        ]
                    )
                    Event.click
                |> ProgramTest.done

Bad habit: selecting by classname

  • Class names aren't helpful to screen reader users
  • We might be clicking a non-interactive element

rtfeldman/elm-css

old computer

rtfeldman/elm-css

<div class="Interests-Page-InterestsClass">
  Beyonce
</div>
viewInterest : String -> Html msg
viewInterest interest =
    li
        [ class [ InterestButtonClass ] ]
        [ text interest ]

Enabling me to do...

spec : Test
spec =
    test "shows the interest page" <|
        \_ ->
            ProgramTest.createDocument
                { init = init
                , view = view
                , update = update
                }
                |> ProgramTest.start testFlags
                |> ProgramTest.simulateDomEvent
                    (Query.find
                        [ Selector.class "InterestButtonClass"
                        ]
                    )
                    Event.click
                |> ProgramTest.done

But then...

Dramatic squirrel

Elm CSS 13.0 arrived

Suddenly, styles lived inline!

<div class="_6206614">Beyonce</div>
viewInterest : String -> Html msg
viewInterest interest =
    li
        [ css
            [ backgroundImage "so_interesting.gif"
            ]
        ]
        [ text interest ]

Does this mean I can't write tests anymore?

grumpy cat

So, I started doing something like this...

<div class="_6206614 good_ole_dependable_class">
  Beyonce
</div>
viewInterest : String -> Html msg
viewInterest interest =
    li
        [ class "good_ole_dependable_class"
        , css
            [ backgroundImage "so_interesting.gif"
            ]
        ]
        [ text interest ]

Wait... isn't there a better way to do this?

The test (before)

Text

spec : Test
spec =
    test "shows the interest page" <|
        \_ ->
            ProgramTest.createDocument
                { init = init
                , view = view
                , update = update
                }
                |> ProgramTest.start testFlags
                |> ProgramTest.simulateDomEvent
                    (Query.find
                        [ Selector.class "InterestButtonClass"
                        ]
                    )
                    Event.click
                |> ProgramTest.done

The test (after)

Text

spec : Test
spec =
    test "shows the interest page" <|
        \_ ->
            ProgramTest.createDocument
                { init = init
                , view = view
                , update = update
                }
                |> ProgramTest.start testFlags
                |> ProgramTest.clickButton "Select Beyonce"
                |> ProgramTest.done

Wait so...

writing a test to enforce accessibility was easier than what I've been doing?

❌ We've got a failing test!

🕵️‍♀️ Original "Button"

selectInterestButton : Interest -> Html Msg
selectInterestButton interest =
    li
        [ onClick interest.onClick
        , css
            [ backgroundImage interest.image
            ]
        ]
        [ text interest.name ]
li : List (Attribute msg) -> List (Html msg) -> Html msg

elm/html

(and styled html, too)

Already awesome, because we produce valid HTML markup by default but...

li : List (Attribute msg) -> List (Html msg) -> Html msg

elm/html

(and Html.Styled, too)

li : List (Attribute Never) -> List (Html msg) -> Html msg

tesk9/accessible-html

(and tesk9/accessible-html-with-css)

This argument is a list of type:

    List (Html.Styled.Attribute Msg)

But `div` needs the 1st argument to be:

    List (Html.Styled.Attribute Never)
import Accessibility.Styled exposing (..)

...

selectInterestButton : Interest -> Html Msg
selectInterestButton interest =
    li
        [ onClick interest.onClick
        , css
            [ backgroundImage interest.image
            ]
        ]
        [ text interest.name ]

Make accessibility your compiler's habit.

import Accessibility.Styled exposing (..)

...

selectInterestButton : Interest -> Html Msg
selectInterestButton interest =
    button
        [ onClick interest.onClick
        , css
            [ backgroundImage interest.image
            ]
        ]
        [ text ("Select " ++ interest.name) ]

✅ Our test passes!

It isn't all buttons

deselecting interests, without styles

⚡️The power of invisibility

invisible : List (Attribute msg)

Makes content invisible without making it inaccessible.

⚡️The power of invisibility

import Accessibility.Styled.Style exposing (invisible)

...

deselectInterestButton : Interest -> Html Msg
deselectInterestButton interest =
    button
        [ onClick interest.onClick
        , css
            [ backgroundImage interest.image
            ]
        ]
        [ span invisible
            [ text ("Deselect " ++ interest.name)
            ]
        ]

Turns out... Elm is a great language for testing and implementing accessible features!

Elm nudges us towards good patterns.

 

These packages help extend Elm's capability

The final test flow

spec : Test
spec =
    test "shows the interest page" <|
        \_ ->
            ProgramTest.createDocument
                { init = init
                , view = view
                , update = update
                }
                |> ProgramTest.start testFlags
                |> ProgramTest.clickButton "Select Beyonce"
                |> ProgramTest.clickButton "Deselect Beyonce"
                ...
                |> ProgramTest.clickButton "Continue"
                |> ProgramTest.done

👩‍🎨

The Results

Before (selecting interests)

selecting interests, unstyled

After (selecting interests)

Before (deselecting interests)

After (deselecting interests)

The true test - does it work on a screen reader?

 

https://youtu.be/oM-h0hTGFXI

Back to habits

  • ✅ Tried
  • ✅ Succeeded
  • ✅ Kept after a month

Was that too small?

Brooke, all you did was add a few buttons and labels!

Was that too small?

Tiny habits that you keep are more impactful than sweeping resolutions that you give up.

❤️

I invite you to make an accessibility goal of your own this month!

💡 Ideas

Pick an item from the https://a11yproject.com/checklist/ and use it in your code

 Switch to `tesk9/accessible-html` if your team is open to new Elm Packages

import Accessibility.Html as Html

   Advocate for accessibility training at your workplace once a week

 Download a browser extension like AXE and check every page you’re working on

Doing small things is better than doing no things!

Thank you!

Tell me about your accessibility habit

@brooke in the Elm Slack!

And a special thanks to...

  • 📦 Tessa Kelly, Aaron Vonderhaar, and Richard Feldman for writing accessible Elm Packages
  • 🗣 Matthew Griffith for all the great feedback
  • Katie Hughes for being my project collaborator (that's the Squirrel emoji, apparently)
  • 🎉 All of the awesome Elm Conf organizers!

A Month of Accessible Elm

By Brooke Angel

A Month of Accessible Elm

  • 75
Loading comments...