diff --git a/web/.eslintrc.js b/web/.eslintrc.js
index 112d9f98..5d7f5a4c 100644
--- a/web/.eslintrc.js
+++ b/web/.eslintrc.js
@@ -1,7 +1,15 @@
module.exports = {
parser: 'babel-eslint',
- extends: ['eslint:recommended', 'plugin:prettier/recommended'],
- plugins: ['react', 'prettier'],
+ extends: [
+ 'eslint:recommended',
+ 'plugin:jsx-a11y/recommended',
+ 'plugin:prettier/recommended',
+ ],
+ plugins: [
+ 'react',
+ 'jsx-a11y',
+ 'prettier',
+ ],
env: {
browser: true,
node: true,
diff --git a/web/app/common/accessibility.js b/web/app/common/accessibility.js
new file mode 100644
index 00000000..c4bf4ab2
--- /dev/null
+++ b/web/app/common/accessibility.js
@@ -0,0 +1,13 @@
+const handleBtnKeyPress = (event, handler) => {
+ if (event.key === ' ' || event.key === 'Enter') {
+ event.preventDefault();
+ handler && handler();
+ }
+};
+
+export const getHandleClickProps = handler => ({
+ role: 'button',
+ tabIndex: 0,
+ onClick: handler,
+ onKeyPress: event => handleBtnKeyPress(event, handler),
+});
diff --git a/web/app/components/auth-panel/auth-panel.jsx b/web/app/components/auth-panel/auth-panel.jsx
index 3755040e..2a1e3d52 100644
--- a/web/app/components/auth-panel/auth-panel.jsx
+++ b/web/app/components/auth-panel/auth-panel.jsx
@@ -2,6 +2,7 @@
import { h, Component } from 'preact';
import { PROVIDER_NAMES } from 'common/constants';
+import { getHandleClickProps } from 'common/accessibility';
export default class AuthPanel extends Component {
constructor(props) {
@@ -41,11 +42,11 @@ export default class AuthPanel extends Component {
{loggedIn && (
You signed in as{' '}
-
+
{user.name}
{isUserIdVisible && ({user.id})}.{' '}
-
+
Sign out?
@@ -62,9 +63,8 @@ export default class AuthPanel extends Component {
{comma}
props.onSignIn(provider))}
role="link"
- tabIndex="0"
- onClick={() => props.onSignIn(provider)}
>
{PROVIDER_NAMES[provider]}
@@ -79,9 +79,8 @@ export default class AuthPanel extends Component {
{user.admin && (
{isBlockedVisible ? 'Hide' : 'Show'} blocked
@@ -91,16 +90,16 @@ export default class AuthPanel extends Component {
Sort by{' '}
-
+
diff --git a/web/app/components/blocked-users/blocked-users.jsx b/web/app/components/blocked-users/blocked-users.jsx
index 82a87606..3bbeb02f 100644
--- a/web/app/components/blocked-users/blocked-users.jsx
+++ b/web/app/components/blocked-users/blocked-users.jsx
@@ -2,6 +2,7 @@
import { h, Component } from 'preact';
import api from 'common/api';
+import { getHandleClickProps } from 'common/accessibility';
export default class BlockedUsers extends Component {
constructor(props) {
@@ -51,12 +52,16 @@ export default class BlockedUsers extends Component {
{user.name}{' '}
({user.id})
{isUserUnblocked && (
- this.block(user)}>
+ this.block(user))}
+ className="blocked-users__action">
block
)}
{!isUserUnblocked && (
- this.unblock(user)}>
+ this.unblock(user))}
+ className="blocked-users__action">
unblock
)}
diff --git a/web/app/components/comment/comment.jsx b/web/app/components/comment/comment.jsx
index cc48f897..e56589ea 100644
--- a/web/app/components/comment/comment.jsx
+++ b/web/app/components/comment/comment.jsx
@@ -2,6 +2,7 @@
import { h, Component } from 'preact';
import api from 'common/api';
+import { getHandleClickProps } from 'common/accessibility';
import { API_BASE, BASE_URL, COMMENT_NODE_CLASSNAME_PREFIX } from 'common/constants';
import { url } from 'common/settings';
import store from 'common/store';
@@ -416,7 +417,11 @@ export default class Comment extends Component {
)}
{mods.view !== 'user' && (
-
+
{o.user.name}
)}
@@ -424,7 +429,7 @@ export default class Comment extends Component {
{isAdmin &&
mods.view !== 'user' && (
+ >
+ {' '}
+
)}
{isAdmin && userBlocked && mods.view !== 'user' && Blocked}
@@ -459,9 +466,8 @@ export default class Comment extends Component {
{!mods.disabled &&
mods.view !== 'user' && (
{mods.collapsed ? '+' : '−'}
@@ -474,10 +480,8 @@ export default class Comment extends Component {
{},
{ type: 'up', selected: scoreIncreased, disabled: isGuest || isCurrentUser }
)}
- role="button"
aria-disabled={isGuest || isCurrentUser}
- tabIndex="0"
- onClick={isGuest || isCurrentUser ? null : this.increaseScore}
+ {...getHandleClickProps(isGuest || isCurrentUser ? null : this.increaseScore)}
title={
isGuest
? 'Only authorized users are allowed to vote'
@@ -495,15 +499,13 @@ export default class Comment extends Component {
+
{isReplying ? 'Cancel' : 'Reply'}
)}
@@ -536,10 +538,8 @@ export default class Comment extends Component {
(!!editTimeLeft || isEditing) &&
mods.view !== 'user' && (
{isEditing ? 'Cancel' : 'Edit'}
{editTimeLeft && ` (${editTimeLeft})`}
@@ -550,31 +550,31 @@ export default class Comment extends Component {
isAdmin && (
{!pinned && (
-
+
Pin
)}
{pinned && (
-
+
Unpin
)}
{userBlocked && (
-
+
Unblock
)}
{!userBlocked && (
-
+
Block
)}
{!deleted && (
-
+
Delete
)}
@@ -587,7 +587,7 @@ export default class Comment extends Component {
{isReplying &&
mods.view !== 'user' && (
-
+
)}
{isEditing &&
@@ -600,7 +600,6 @@ export default class Comment extends Component {
id={o.id}
value={o.orig}
errorMessage={!editTimeLeft && 'Editing time has expired.'}
- autoFocus
/>
)}
diff --git a/web/app/components/input/input.jsx b/web/app/components/input/input.jsx
index 69452004..b8e28069 100644
--- a/web/app/components/input/input.jsx
+++ b/web/app/components/input/input.jsx
@@ -134,7 +134,7 @@ export default class Input extends Component {
const { mods = {}, value = null, errorMessage } = props;
return (
-