Skip to content

Instantly share code, notes, and snippets.

@chrisjpatty
Last active May 26, 2020 19:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chrisjpatty/69804ee54e3fd262842bc9bb2049e421 to your computer and use it in GitHub Desktop.
Save chrisjpatty/69804ee54e3fd262842bc9bb2049e421 to your computer and use it in GitHub Desktop.
A React component for announcing messages to a screen reader that are visually hidden from users. This component comes with development warnings for invalid usages. As these messages are unnecessary in production, I recommend using a Webpack or Rollup plugin that will exclude the warnings from production builds such as https://www.npmjs.com/pack…
.visually-hidden {
position: absolute;
left: -10000px;
top: auto;
width: 1px;
height: 1px;
overflow: hidden;
color: transparent;
opacity: .01;
}
import React from 'react'
import PropTypes from 'prop-types'
const Announcer = ({ message, method = 'polite' }) => {
const previousMethod = usePrevious(method)
const componentHasMounted = React.useRef(false)
React.useEffect(() => {
if (componentHasMounted.current && method !== previousMethod) {
console.error(
`The value of the "method" prop was changed from ${previousMethod} to ${method}. This prop should not change over the lifecycle of this component.`
)
}
}, [method])
React.useEffect(() => {
if (message) {
console.warn(
`The <Announcer/> was mounted with a message, but this message may not be read to screen readers as the aria-live region has not yet mounted. To ensure that messages are announced, mount this component with no message, and then supply it with a message in a later render to trigger the announcement.`
)
}
componentHasMounted.current = true;
}, [])
return (
<div aria-live={method} role="status" className="visually-hidden">
{message}
</div>
)
}
Announcer.propTypes = {
message: PropTypes.string.isRequired,
method: PropTypes.oneOf(['polite', 'assertive'])
}
export default Announcer
export const usePrevious = value => {
const ref = React.useRef();
React.useEffect(() => {
ref.current = value;
}, [value]);
return ref.current;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment