Skip to content

Commit

Permalink
Improve accessibility (#1471)
Browse files Browse the repository at this point in the history
Includes:

1) Adds lang attribute to container div. Ideally we'd set lang on the html tag. However lock can appear as a modal in an external sites html, so next best thing is to set lang on the container div
2) Adjusts the markup and styling of the 'Login' / 'Signup' tabs to improve keyboard navigation. The tabs now have role 'navigation. If a tab is focused it has different styling. The current tab is no longer a link
3) Some svgs have been give aria-hidden"true". They are decoration so hiding them from screen readers seems sensible
4) The box Button component has been changed from a 'span' to a 'button' so that it can be navigated to with a keyboard. Also, it's been styled to look different when focused.
5) The submit button has been given a label
6) Empty alt tag on the logo img in the header (it's arguably decoration)
7) Aria tags on form inputs
8) Linking of form errors to their inputs via aria. Use of role='alert' on form errors for screenreaders.
  • Loading branch information
andrew-me authored and luisrudge committed Aug 28, 2018
1 parent 5453674 commit 1c9bcc2
Show file tree
Hide file tree
Showing 17 changed files with 66 additions and 23 deletions.
13 changes: 11 additions & 2 deletions css/index.styl
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ tabsHeight = 40px
border-radius 100px
height 10px
width 10px
padding 0
position absolute
top 14px
right 14px
Expand All @@ -176,6 +177,9 @@ tabsHeight = 40px
border 6px solid white
cursor pointer
line-height 0

&:focus
box-shadow 0 3px 3px rgba(0,0,0,.3)

svg
-webkit-box-sizing content-box
Expand Down Expand Up @@ -322,6 +326,8 @@ tabsHeight = 40px
color rgba(0,0,0,.87)
cursor pointer
margin-bottom 0
&:focus
text-decoration underline

.auth0-lock-input-block
position relative
Expand Down Expand Up @@ -1142,18 +1148,21 @@ tabsHeight = 40px
text-align center
cursor pointer

a
a, span
padding 11px 10px
display block
text-decoration none
color rgba(#5C666F,.6)
font-weight 500

a:focus
color rgba(#5C666F,.9)

&.auth0-lock-tabs-current
box-shadow 0 1px 0 0 #5C666F
cursor default

a
span
color #5C666F

// password strength
Expand Down
12 changes: 8 additions & 4 deletions src/connection/database/login_sign_up_tabs.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export default class LoginSignUpTabs extends React.Component {
const isLogin = getScreen(lock) === 'login';

return (
<div className="auth0-lock-tabs-container">
<div role="navigation" className="auth0-lock-tabs-container">
<ul className="auth0-lock-tabs">
<LoginSignUpTab
label={loginLabel}
Expand Down Expand Up @@ -69,9 +69,13 @@ class LoginSignUpTab extends React.Component {

return (
<li className={className}>
<a href={href || 'javascript:void(0)'} onClick={::this.handleClick}>
{label}
</a>
{current ? (
<span>{label}</span>
) : (
<a href={href || 'javascript:void(0)'} onClick={::this.handleClick}>
{label}
</a>
)}
</li>
);
}
Expand Down
1 change: 1 addition & 0 deletions src/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ export default class Base extends EventEmitter {
isMobile: l.ui.mobile(m),
isModal: l.ui.appendContainer(m),
isSubmitting: l.submitting(m),
language: l.ui.language(m),
logo: l.ui.logo(m),
primaryColor: l.ui.primaryColor(m),
screenName: screen.name,
Expand Down
7 changes: 4 additions & 3 deletions src/ui/box/button.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,20 @@ import React from 'react';

const svgs = {
back:
'<svg focusable="false" enable-background="new 0 0 24 24" version="1.0" viewBox="0 0 24 24" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <polyline fill="none" points="12.5,21 3.5,12 12.5,3 " stroke="#000000" stroke-miterlimit="10" stroke-width="2"></polyline> <line fill="none" stroke="#000000" stroke-miterlimit="10" stroke-width="2" x1="22" x2="3.5" y1="12" y2="12"></line> </svg>',
'<svg aria-hidden="true" focusable="false" enable-background="new 0 0 24 24" version="1.0" viewBox="0 0 24 24" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <polyline fill="none" points="12.5,21 3.5,12 12.5,3 " stroke="#000000" stroke-miterlimit="10" stroke-width="2"></polyline> <line fill="none" stroke="#000000" stroke-miterlimit="10" stroke-width="2" x1="22" x2="3.5" y1="12" y2="12"></line> </svg>',
close:
'<svg focusable="false" enable-background="new 0 0 128 128" version="1.1" viewBox="0 0 128 128" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><g><polygon fill="#373737" points="123.5429688,11.59375 116.4765625,4.5185547 64.0019531,56.9306641 11.5595703,4.4882813 4.4882813,11.5595703 56.9272461,63.9970703 4.4570313,116.4052734 11.5244141,123.4814453 63.9985352,71.0683594 116.4423828,123.5117188 123.5126953,116.4414063 71.0732422,64.0019531 "></polygon></g></svg>'
'<svg aria-hidden="true" focusable="false" enable-background="new 0 0 128 128" version="1.1" viewBox="0 0 128 128" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><g><polygon fill="#373737" points="123.5429688,11.59375 116.4765625,4.5185547 64.0019531,56.9306641 11.5595703,4.4882813 4.4882813,11.5595703 56.9272461,63.9970703 4.4570313,116.4052734 11.5244141,123.4814453 63.9985352,71.0683594 116.4423828,123.5117188 123.5126953,116.4414063 71.0732422,64.0019531 "></polygon></g></svg>'
};

const IconButton = ({ name, onClick, svg }) => (
<span
<button
className={`auth0-lock-${name}-button`}
dangerouslySetInnerHTML={{ __html: svg }}
onClick={e => {
e.preventDefault();
onClick();
}}
aria-label={name}
/>
);

Expand Down
5 changes: 3 additions & 2 deletions src/ui/box/chrome.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import * as l from '../../core/index';
import Header from './header';

const submitSvg =
'<svg focusable="false" width="43px" height="42px" viewBox="0 0 43 42" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns"><g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage"><g id="Lock" sketch:type="MSArtboardGroup" transform="translate(-280.000000, -3592.000000)"><g id="SMS" sketch:type="MSLayerGroup" transform="translate(153.000000, 3207.000000)"><g id="Group" sketch:type="MSShapeGroup"><g id="Login" transform="translate(0.000000, 369.000000)"><g id="Btn"><g id="Oval-302-+-Shape" transform="translate(128.000000, 17.000000)"><circle id="Oval-302" stroke="#FFFFFF" stroke-width="2" cx="20.5" cy="20" r="20"></circle><path d="M17.8,15.4 L19.2,14 L25.2,20 L19.2,26 L17.8,24.6 L22.4,20 L17.8,15.4 Z" id="Shape" fill="#FFFFFF"></path></g></g></g></g></g></g></g></svg>';
'<svg aria-hidden="true" focusable="false" width="43px" height="42px" viewBox="0 0 43 42" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns"><g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage"><g id="Lock" sketch:type="MSArtboardGroup" transform="translate(-280.000000, -3592.000000)"><g id="SMS" sketch:type="MSLayerGroup" transform="translate(153.000000, 3207.000000)"><g id="Group" sketch:type="MSShapeGroup"><g id="Login" transform="translate(0.000000, 369.000000)"><g id="Btn"><g id="Oval-302-+-Shape" transform="translate(128.000000, 17.000000)"><circle id="Oval-302" stroke="#FFFFFF" stroke-width="2" cx="20.5" cy="20" r="20"></circle><path d="M17.8,15.4 L19.2,14 L25.2,20 L19.2,26 L17.8,24.6 L22.4,20 L17.8,15.4 Z" id="Shape" fill="#FFFFFF"></path></g></g></g></g></g></g></g></svg>';
const submitText =
'<svg focusable="false" class="icon-text" width="8px" height="12px" viewBox="0 0 8 12" version="1.1" xmlns="http://www.w3.org/2000/svg"><g id="Symbols" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"><g id="Web/Submit/Active" transform="translate(-148.000000, -32.000000)" fill="#FFFFFF"><polygon id="Shape" points="148 33.4 149.4 32 155.4 38 149.4 44 148 42.6 152.6 38"></polygon></g></g></svg>';
'<svg aria-hidden="true" focusable="false" class="icon-text" width="8px" height="12px" viewBox="0 0 8 12" version="1.1" xmlns="http://www.w3.org/2000/svg"><g id="Symbols" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"><g id="Web/Submit/Active" transform="translate(-148.000000, -32.000000)" fill="#FFFFFF"><polygon id="Shape" points="148 33.4 149.4 32 155.4 38 149.4 44 148 42.6 152.6 38"></polygon></g></g></svg>';

class SubmitButton extends React.Component {
handleSubmit() {
Expand Down Expand Up @@ -58,6 +58,7 @@ class SubmitButton extends React.Component {
onClick={::this.handleSubmit}
name="submit"
type="submit"
aria-label={label ? label : 'Submit'}
>
<div className="auth0-loading-container">
<div className="auth0-loading" />
Expand Down
4 changes: 3 additions & 1 deletion src/ui/box/container.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ export default class Container extends React.Component {
}

return (
<div className={className}>
<div className={className} lang={this.props.language}>
{overlay}
<div className="auth0-lock-center">
<form className="auth0-lock-widget" method="post" onSubmit={::this.handleSubmit}>
Expand Down Expand Up @@ -259,6 +259,7 @@ Container.propTypes = {
isMobile: PropTypes.bool.isRequired,
isModal: PropTypes.bool.isRequired,
isSubmitting: PropTypes.bool.isRequired,
language: PropTypes.string,
logo: PropTypes.string.isRequired,
primaryColor: PropTypes.string.isRequired,
screenName: PropTypes.string.isRequired,
Expand All @@ -285,6 +286,7 @@ export const defaultProps = (Container.defaultProps = {
disableSubmitButton: false,
isMobile: false,
isSubmitting: false,
language: 'en',
logo: `${
isFileProtocol ? 'https:' : ''
}//cdn.auth0.com/styleguide/components/1.0.8/media/logos/img/badge.png`,
Expand Down
2 changes: 1 addition & 1 deletion src/ui/box/header.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class Welcome extends React.Component {
render() {
const { name, imageUrl, title } = this.props;
const imgClassName = !!title ? 'auth0-lock-header-logo' : 'auth0-lock-header-logo centered';
const img = <img className={imgClassName} src={imageUrl} />;
const img = <img alt="" className={imgClassName} src={imageUrl} />;
const welcome = title ? <WelcomeMessage title={title} name={name} /> : null;

return (
Expand Down
5 changes: 4 additions & 1 deletion src/ui/input/email_input.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react';
import InputWrap from './input_wrap';

const svg =
'<svg focusable="false" width="14px" height="13px" viewBox="0 0 32 26" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns" class="auth0-lock-icon auth0-lock-icon-box"><g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage"><g id="32px" sketch:type="MSLayerGroup" transform="translate(-2155.000000, -2317.000000)" fill="#373A39"><g id="Group-856" transform="translate(1.000000, 1.000000)" sketch:type="MSShapeGroup"><path id="Fill-419" d="M2184,2339 C2184,2339.55 2183.55,2340 2183,2340 L2157,2340 C2156.45,2340 2156,2339.55 2156,2339 L2156,2319 C2156,2318.45 2156.45,2318 2157,2318 L2183,2318 C2183.55,2318 2184,2318.45 2184,2319 L2184,2339 L2184,2339 Z M2184,2316 L2156,2316 C2154.89,2316 2154,2316.89 2154,2318 L2154,2340 C2154,2341.1 2154.89,2342 2156,2342 L2184,2342 C2185.1,2342 2186,2341.1 2186,2340 L2186,2318 C2186,2316.89 2185.1,2316 2184,2316 L2184,2316 Z M2176,2322 L2180,2322 L2180,2326 L2176,2326 L2176,2322 Z M2174,2328 L2182,2328 L2182,2320 L2174,2320 L2174,2328 Z M2158,2332 L2172,2332 L2172,2330 L2158,2330 L2158,2332 Z M2158,2336 L2172,2336 L2172,2334 L2158,2334 L2158,2336 Z"></path></g></g></g></svg>';
'<svg aria-hidden="true" focusable="false" width="14px" height="13px" viewBox="0 0 32 26" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns" class="auth0-lock-icon auth0-lock-icon-box"><g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage"><g id="32px" sketch:type="MSLayerGroup" transform="translate(-2155.000000, -2317.000000)" fill="#373A39"><g id="Group-856" transform="translate(1.000000, 1.000000)" sketch:type="MSShapeGroup"><path id="Fill-419" d="M2184,2339 C2184,2339.55 2183.55,2340 2183,2340 L2157,2340 C2156.45,2340 2156,2339.55 2156,2339 L2156,2319 C2156,2318.45 2156.45,2318 2157,2318 L2183,2318 C2183.55,2318 2184,2318.45 2184,2319 L2184,2339 L2184,2339 Z M2184,2316 L2156,2316 C2154.89,2316 2154,2316.89 2154,2318 L2154,2340 C2154,2341.1 2154.89,2342 2156,2342 L2184,2342 C2185.1,2342 2186,2341.1 2186,2340 L2186,2318 C2186,2316.89 2185.1,2316 2184,2316 L2184,2316 Z M2176,2322 L2180,2322 L2180,2326 L2176,2326 L2176,2322 Z M2174,2328 L2182,2328 L2182,2320 L2174,2320 L2174,2328 Z M2158,2332 L2172,2332 L2172,2330 L2158,2330 L2158,2332 Z M2158,2336 L2172,2336 L2172,2334 L2158,2334 L2158,2336 Z"></path></g></g></g></svg>';

export default class EmailInput extends React.Component {
constructor(props) {
Expand Down Expand Up @@ -45,6 +45,9 @@ export default class EmailInput extends React.Component {
onChange={::this.handleOnChange}
onFocus={::this.handleFocus}
onBlur={::this.handleBlur}
aria-label="Email"
aria-invalid={!isValid}
aria-describedby={`auth0-lock-error-msg-email`}
{...props}
/>
</InputWrap>
Expand Down
4 changes: 2 additions & 2 deletions src/ui/input/input_wrap.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export default class InputWrap extends React.Component {
let iconElement = null;

if (typeof icon === 'string') {
iconElement = <span dangerouslySetInnerHTML={{ __html: icon }} />;
iconElement = <span aria-hidden="true" dangerouslySetInnerHTML={{ __html: icon }} />;
} else if (icon) {
iconElement = icon;
}
Expand All @@ -30,7 +30,7 @@ export default class InputWrap extends React.Component {

const errorTooltip =
!isValid && invalidHint ? (
<div className="auth0-lock-error-msg">
<div role="alert" id={`auth0-lock-error-msg-${name}`} className="auth0-lock-error-msg">
<span>{invalidHint}</span>
</div>
) : null;
Expand Down
Loading

0 comments on commit 1c9bcc2

Please sign in to comment.