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