Skip to content

Commit

Permalink
Fixed Keyboard Accessibility for Passwords
Browse files Browse the repository at this point in the history
Updated the styles for the text field's password button to show an
outline when the user has tab focused the button.
  • Loading branch information
mlaursen committed Dec 8, 2016
1 parent 2c4e111 commit 807aa2a
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 1 deletion.
53 changes: 53 additions & 0 deletions src/js/TextFields/PasswordButton.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { PureComponent, PropTypes } from 'react';
import cn from 'classnames';

import { TAB, SPACE, ENTER } from '../constants/keyCodes';
import FontIcon from '../FontIcons/FontIcon';

export default class PasswordButton extends PureComponent {
Expand All @@ -9,16 +10,68 @@ export default class PasswordButton extends PureComponent {
passwordVisible: PropTypes.bool,
iconClassName: PropTypes.string,
iconChildren: PropTypes.node,
onKeyUp: PropTypes.func,
onKeyDown: PropTypes.func,
};

constructor(props) {
super(props);

this.state = { keyboardFocus: false };

this._handleKeyUp = this._handleKeyUp.bind(this);
this._handleKeyDown = this._handleKeyDown.bind(this);
this._handleOutsideClick = this._handleOutsideClick.bind(this);
}

componentWillUnmount() {
if (this.state.keyboardFocus) {
window.removeEventListener('click', this._handleOutsideClick);
}
}

_handleOutsideClick(e) {
if (this._button && !this._button.contains(e.target)) {
window.removeEventListener('click', this._handleOutsideClick);
this.setState({ keyboardFocus: false });
}
}

_handleKeyUp(e) {
if (this.props.onKeyUp) {
this.props.onKeyUp(e);
}

if ((e.which || e.keyCode) === TAB) {
window.addEventListener('click', this._handleOutsideClick);
this.setState({ keyboardFocus: true });
}
}

_handleKeyDown(e) {
if (this.props.onKeyDown) {
this.props.onKeyDown(e);
}

const key = e.which || e.keyCode;
if (key === TAB || key === ENTER || key === SPACE) {
window.removeEventListener('click', this._handleOutsideClick);
this.setState({ keyboardFocus: false });
}
}

render() {
const { keyboardFocus } = this.state;
const { active, passwordVisible, iconClassName, iconChildren, ...props } = this.props;

return (
<button
{...props}
onKeyDown={this._handleKeyDown}
onKeyUp={this._handleKeyUp}
type="button"
className={cn('md-text-field-inline-indicator md-password-btn md-pointer--hover', {
'md-password-btn--focus': keyboardFocus,
'md-password-btn--active': active,
'md-password-btn--invisible': active && !passwordVisible,
})}
Expand Down
2 changes: 1 addition & 1 deletion src/scss/components/_text-fields.scss
Original file line number Diff line number Diff line change
Expand Up @@ -1247,7 +1247,7 @@ $md-text-field-desktop-floating-label-margin: 33px;
padding: 0;
width: $md-font-icon-size;

&:focus {
&:not(.md-password-btn--focus):focus {
outline: none;
}

Expand Down

0 comments on commit 807aa2a

Please sign in to comment.