Tessa Kelly

Engineer at NoRedInk

@t_kelly9

 

Accessibility with Elm

 

What

Is

accessibility?

 

(Not this presentation so far)

 

Tessa Kelly

Engineer at NoRedInk

@t_kelly9

Accessibility with Elm

Follow along with these slides at:

slides.com/tessak/elm/live

 

What

is accessibility?

-- TODO: talk a11y

  • Accessibility specifications
  • Building an Elm accessibility library
  • Coding accessibly

to

Choose

accessibility

Wai-WCAG 2.0

Web accessibility initiative

Web Content Accessibility Guidelines

P

O

U

R

erceivable

perable

nderstandable

Obust

Wai-aria

Web accessibility initiative

Accessible Rich Internet Applications

Wai-aria

  • Roles
  • States & Properties
  • Managing Focus

W3C Candidate Recommendation​

https://www.w3.org/TR/wai-aria-1.1

https://slides.com/tessak/elm/live

(just in case)

elm-html-a11y

Elm Html Accessibility

tesk9/elm-html-a11y

Module Naming

-- elm-lang/html design patterns

import Html
import Html.Attributes


-- tesk9/elm-html-a11y design patterns

import Html.A11y
import Html.Attributes.A11y

Standardized API

-- elm-lang/html design patterns

img : List (Html.Attribute msg) -> List (Html msg) -> Html msg

-- tesk9/elm-html-a11y design patterns

img : String -> List (Html.Attribute msg) -> Html msg

decorativeImg : List (Html.Attribute msg) -> Html msg

Limiting arguments

-- tesk9/elm-html-a11y design patterns

autoCompleteInline : Attribute msg

autoCompleteList : Attribute msg

autoCompleteBoth : Attribute msg

Accessible-html

Accessible html

tesk9/accessible-html

Module Naming

-- tesk9/elm-html-a11y design patterns

import Html.A11y
import Html.Attributes.A11y


-- tesk9/accessible-html design patterns

import Accessibility
import Accessibility.Aria
import Accessibility.Key
import Accessibility.Landmark
import Accessibility.Live
import Accessibility.Role
import Accessibility.Style

A Different kind of Standardized API

-- elm-lang/html design patterns

img : List (Html.Attribute msg) -> List (Html msg) -> Html msg

-- tesk9/elm-html-a11y design patterns

img : String -> List (Html.Attribute msg) -> Html msg

-- tesk9/accessible-html design patterns

img : String -> List (Html.Attribute Never) -> Html msg

Writing

Accessible

HTML Widgets

P

O

U

R

erceivable

perable

nderstandable

Obust

PErceivable

import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (..)


main : Platform.Program Basics.Never Bool Bool

...

view : Bool -> Html Bool
view showTooltip =
    div [ class "tooltip-container" ]
        [ div
            [ class "inexplicable-content"
            , onMouseEnter True
            , onMouseLeave False
            ]
            []
        , if showTooltip then
            div [ class "tooltip" ]
                [ text "Rainbow linear gradient nonsense!!!" ]
          else
            text ""
        ]
    

https://ellie-app.com/8Sm5LkL4Qa1/0

PErceivable

import Accessibility
import Accessibility.Aria exposing (describedBy)
import Accessibility.Role exposing (toolTip)

view showTooltip =
    div [ class "tooltip-container" ]
        [ div
            [ class "inexplicable-content"
            , describedBy [ "awesome-tooltip-numbah-1" ]
            , onMouseEnter True
            , onMouseLeave False
            ]
            []
        , if showTooltip then
            div
                [ id "awesome-tooltip-numbah-1"
                , class "tooltip"
                , toolTip
                ]
                [ text "Rainbow linear gradient nonsense!!!" ]
          else
            text ""
        ]

https://ellie-app.com/8c6ts4XVwa1/1

A Brief side-adventure into role-playing

From role to element

import Accessibility.Role exposing (progressBar)
import Accessibility.Widget exposing (valueMax, valueMin, valueNow)
import Html.Attributes exposing (..)

    div
        [ progressBar
        , valueMin 0
        , valueMax 100
        , valueNow 30
        , style
            [ ( "width", "160px" )
            , ( "height", "10px" )
            , ( "background-color", "gray" )
            ]
        ]
        [ div
            [ style
                [ ( "width", "30%" )
                , ( "height", "100%" )
                , ( "background-color", "blue" )
                ]
            ]
            []
        ]
import Html exposing (..)
import Html.Attributes exposing (..)


progressBarElement : Html msg
progressBarElement =
    progress [ value "30", Html.Attributes.max "100" ] []

Operability

import Accessibility.Key exposing (escape, onKeyDown, space, tabbable)

view showTooltip =
    div [ class "tooltip-container" ]
        [ div
            [ class "inexplicable-content"
            , tabbable True
            , describedBy [ "awesome-tooltip-numbah-1" ]
            , onFocus True
            , onBlur False
            , onKeyDown [ space True, escape False ]
            , onMouseEnter True
            , onMouseLeave False
            ]
            []
        , if showTooltip then
            div
                [ id "awesome-tooltip-numbah-1"
                , class "tooltip"
                , toolTip
                ]
                [ text "Rainbow linear gradient nonsense!!!" ]
          else
            text ""
        ]

https://ellie-app.com/gQVkWBbWya1/0

Operability

Understandable

Radio Buttons

https://ellie-app.com/bLyG86crKa1/1

Tab order

https://ellie-app.com/bLyG86crKa1/2

Managing Focus

import Html exposing (Html, div)
import Html.Attributes exposing (class, tabindex)


main : Html msg
main =
    div
        [ class "container" ]
        [ div [ class "tabbable-div", tabindex 1 ] []
        , div [ class "tabbable-div", tabindex 2 ] []
        , div [ class "tabbable-div", tabindex 3 ] []
        , div [ class "tabbable-div", tabindex 4 ] []
        , div [ class "tabbable-div", tabindex 4 ] []
        , div [ class "tabbable-div", tabindex 3 ] []
        , div [ class "tabbable-div", tabindex 2 ] []
        , div [ class "tabbable-div", tabindex 1 ] []
        ]

Managing Focus, Part 2

-- module Accessibility.Role

tab : Attribute msg


tabList : Attribute msg


tabPanel : Attribute msg
-- module Accessibility.Key

tabbable : Attribute msg

onKeyDown : List (Json.Decoder msg) -> Attribute msg

left : msg -> Json.Decoder msg

right : msg -> Json.Decoder msg
-- module Accessibility.Aria

controls : String -> Html.Attribute msg

labelledBy : String -> Html.Attribute msg

labeledBy : String -> Html.Attribute msg

-- module Accessibility.Widget

selected : Bool -> Html.Attribute msg

Tab Component Imports

import Accessibility exposing (Html, div, text)
import Accessibility.Aria exposing (controls, labelledBy)
import Accessibility.Key
    exposing
        ( left
        , onKeyDown
        , right
        , tabbable
        )
import Accessibility.Role exposing (tab, tabList, tabPanel)
import Accessibility.Widget exposing (selected)
import Html.Attributes exposing (hidden, id)
import Html.Events exposing (onClick)

Tab Component Tab & Panel

-- A tab:


    div
        [ id "tab-0", controls "panel-0", tab, tabbable True ]
        [ text "Tab 0" ]


-- That tab's associated panel:


    div
        [ id "panel-0", labelledBy "tab-0", tabPanel ]
        [ text "Panel 0" ]

Tab Component Tablist

[ div [ tabList ]
    [ div
        [ id "tab-0", controls "panel-0", tab, tabbable True ]
        [ text "Tab 0" ]
    , div
        [ id "tab-1", controls "panel-1", tab, tabbable True ]
        [ text "Tab 1" ]
    , div
        [ id "tab-2", controls "panel-2", tab, tabbable True ]
        [ text "Tab 2" ]
    ]
, div [ id "panel-0", labelledBy "tab-0", tabPanel ]
    [ text "Panel 0" ]
, div [ id "panel-1", labelledBy "tab-1", tabPanel ]
    [ text "Panel 1" ]
, div [ id "panel-2", labelledBy "tab-2", tabPanel ]
    [ text "Panel 2" ]
]

Tab Widget In-Progress

https://ellie-app.com/4bVqFGffMa1/0

-- module Accessibility

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


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


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

From role to element

[ div [ tabList ]
    [ div
        [ id "tab-0", controls "panel-0", tab, tabbable True ]
        [ text "Tab 0" ]
    , div
        [ id "tab-1", controls "panel-1", tab, tabbable True ]
        [ text "Tab 1" ]
    , div
        [ id "tab-2", controls "panel-2", tab, tabbable True ]
        [ text "Tab 2" ]
    ]
, div [ id "panel-0", labelledBy "tab-0", tabPanel ]
    [ text "Panel 0" ]
, div [ id "panel-1", labelledBy "tab-1", tabPanel ]
    [ text "Panel 1" ]
, div [ id "panel-2", labelledBy "tab-2", tabPanel ]
    [ text "Panel 2" ]
]
[ tabList []
    [ tab [ id "tab-0", controls "panel-0" ] [ text "Tab 0" ]
    , tab [ id "tab-1", controls "panel-1" ] [ text "Tab 1" ]
    , tab [ id "tab-2", controls "panel-2" ] [ text "Tab 2" ]
    ]
, tabPanel [ id "panel-0", labelledBy "tab-0" ]
    [ text "Panel 0" ]
, tabPanel [ id "panel-1", labelledBy "tab-1" ]
    [ text "Panel 1" ]
, tabPanel [ id "panel-2", labelledBy "tab-2" ]
    [ text "Panel 2" ]
]

Tab Widget: now with tab selection

type Msg
    = Left
    | Right
    | ById Int


viewTab : ( Int, Bool ) -> Html Msg
viewTab (tabId, isCurrent) =
    tab
        [ id ("tab-" ++ toString tabId)
        , controls ("panel-" ++ toString tabId)
        , selected isCurrent
        , onClick (ById tabId)
        , onKeyDown [ right Right, left Left ]
        ]
        [ text ("Tab " ++ toString tabId) ]

Tab Widget: now with Panel Hiding

type Msg
    = Left
    | Right
    | ById Int


viewTab : ( Int, Bool ) -> Html Msg



viewPanel : ( Int, Bool ) -> Html Msg
viewPanel ( panelId, isCurrent ) =
    tabPanel
        [ id ("panel-" ++ toString panelId)
        , labelledBy ("tab-" ++ toString panelId)
        , hidden (not isCurrent)
        ]
        [ text ("Panel " ++ toString panelId) ]

Tab Widget (Minus styles)

https://ellie-app.com/4bVqFGffMa1/1

[aria-selected="true"] {
    border: 1px solid purple;
    background-color: pink;
}

If it looks like a tab...

Tabby

By Lucarelli (Own work) [GFDL (http://www.gnu.org/copyleft/fdl.html), via Wikimedia Commons

https://commons.wikimedia.org/wiki/File%3AGatto_Piccolo_3.jpg

-- TODO: talk a11y

  • WAI-WCAG POUR principles
  • WAI-ARIA roles, states, and properties
  • elm-html-a11y
  • accessible-html
  • Coding accessibly
    • Tooltips
    • Tabs
    • ...

-- TODO: Learn more!

  • `checkbox`, `radio`, `inputText`, `labelBefore`, `labelAfter`
  • Live regions and Accessibility.Live
  • Widgets
    • Alerts
    • Toggle buttons
    • Dialogs
    • Feeds
    • Grids and Tables
    • Menus
    • Sliders
    • Toolbars
    • ...

-- TODO: Build more!

  • View helpers for all roles
  • Input helpers for all input types
  • Documentation improvements
  • ... that thing you were thinking??? 💕

Accessible-html

Accessible html

tesk9/accessible-html

Open

friendly

Easy-to-use

tesk9/accessible-html

@t_kelly9

THank you!

Elm

By Tessa K

Elm

Accessibility with Elm

  • 1,562