{
  "$type": "site.standard.document",
  "content": {
    "$type": "site.standard.content.markdown",
    "text": "I am a big proponent of component-driven development, and don’t agree with the [utility class method of styling](/posts/classname-soup). In component-driven development, you offer blackbox abstractions of common implementations. Meanwhile, the utility class method allows for more customization. In a systematic approach, we want our experiences to be consistent and therefore follow the same patterns and conventions. Distributing these blackboxes that align with guidelines by default makes a consistent experience easy to create and manage. Whereas, trying to learn and follow guidelines from other resources to implement piecemeal comes with misintereptations and other inconsistencies.\n\nHowever, in this work there has been one concept that I’ve stuggled to put into this component-driven ecosystem; *screenreader only* as it has traditionally existed as a class (eg., `.sr-only`) added to an otherwise benign element.\n\n## Amongst the library\n\nThe purpose of screenreader only is to mark a section of an interface that is meant specifically for assistive technologies to pick up within the experience; invisible to sighted users. Here’s a common example:\n\n```\n<button type=\"button\">\n    <svg\n        focusable=\"false\"\n        aria-hidden=\"true\"\n        viewBox=\"0 0 24 24\">\n    <path\n        d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5\n            6.41 10.59 12 5 17.59 6.41 19 12\n            13.41 17.59 19 19 17.59 13.41 12z\" />\n    </svg>\n    <span class=\"sr-only\">Close</span>\n</button>\n```\n\nIn this example, sighted users will be able to see the path of the `<svg/>` in the shape of an ‘x’ with no other visual information. Non-sighted users who leverage assistive technology should receive “Close” from their tool and ignore the data set by the `<svg/>`. There’s more about this composition and words about screenreader only versus `aria-label` [in this post](https://gomakethings.com/revisting-aria-label-versus-a-visually-hidden-class/#pairing-a-visually-hidden-class-with-aria-hidden) by [Chris Ferdinandi](https://twitter.com/ChrisFerdinandi).\n\nMy gut reaction is that it would be odd to offer such a component that simply applies the styles required to make it hidden and for it to be offered as an exception to an otherwise utility-free ecosystem. However, I don’t like exceptions, I strive for consistent thoughtful systems.\n\nMy first thought is where a `<ScreenreaderOnly/>` would live amongst other components, if it is in fact a component itself. This is assuming that the library is vast and requires subsections that aim to direct visitors to the appropriate component through navigation. First I’d assume this might live with other “accessibility” components. However, this also assumes that folks are actively looking to include accessibility in their experiences; something that we can only dream of across an organization.\n\nFurther, we might consider accessibility as a quality of components, perhaps not a component itself. As I’m having difficulty thinking about other possible memebers of this family that would also be associated with the `<ScreenreaderOnly/>` component.\n\nMy next thought is that because it is a quality, perhaps it isn’t a component but a property on an existing component we set. Because we expect that the content of this conceptual `<ScreenreaderOnly/>` component to only ever be text, it might be safe to consider that it is a property of a text component.\n\n```\n<Text screenreaderOnly>To begin, start by...<Text/>\n```\n\nThe `<Text/>` component will be widely more popular than the possible `<ScreenreaderOnly/>` component, which will cause more folks to potentially visit its API and learn about this helpful feature. This being an opportunity to educate when its use is appropriate.\n\nIn doing the research for this article, I wondered if anyone had considered rethinking “Screenreader Only” as “ARIA only” as it is a shorter name with perhaps better marketing. I do worry that a person would believe that it is a valid ARIA attribute (it’s not) but [I’m not the first to consider the idea for the purpose](https://fylgja.dev/components/aria-only/).\n\n## When is it appropriate\n\nI did quite a bit of reading and research before writing this post. As I’m an advocate for accessibility, I don’t consider myself an expert and definitely have areas of improvement in my practice. I wanted to know when the concept of screenreader only was appropriate if at all.\n\nFor this topic, I highly recommend reading [Scott O’Hara](https://twitter.com/scottohara)’s post called [Inclusively Hidden](https://www.scottohara.me/blog/2017/04/14/inclusively-hidden.html).\n\nIn Scott’s post, he describes some alternatives to screenreader only; specifically one loophole in particular.\n\n> By attaching an `aria-describedby` or `aria-labelledby` attribute to a focusable element, and setting the ARIA attribute’s value to the completely hidden element’s id, screen readers will announce the content of the completely hidden element.\n\nHere’s his example:\n\n```\n<p class=\"visually-hidden\" id=\"example_desc\">\n  Here are specific instructions for the type\n  of information this form input is expecting to receive...\n</p>\n\n<label for=\"example\">\n  Example\n</label>\n<input type=\"text\" id=\"example\" aria-describedby=\"example_desc\">\n```\n\nIn this way, we still need to apply styles to the `.visually-hidden` element in order for it to disappear from view. But this also demonstrates how to connect that content to an interactive element for further context by using `aria-describedby`.\n\nFor completeness, here’s what Scott recommends as the styles for `visually-hidden`:\n\n```\n.visually-hidden:not(:focus):not(:active) {\n  clip: rect(0 0 0 0); \n  clip-path: inset(50%);\n  height: 1px;\n  overflow: hidden;\n  position: absolute;\n  white-space: nowrap; \n  width: 1px;\n}\n```\n\nI’m now imagining some sort of interface for when `screenreaderOnly` is used on the `<Text/>` component to ensure it is connected to *something*.\n\n```\n// Source\nfunction Text({ screenreaderOnly, children }) {\n    /**\n     * We wouldn't want to always add an id to all text\n     * instead we'd add conditionally for screenreaderOnly.\n     * This is just for this example.\n     */\n    const id = React.useId();\n\n    React.useEffect(() => {\n        /**\n         * Consider appending the id instead of replacing\n         * `aria-describedby` can accept space separated ids\n         */\n        screenreaderOnly\n            ?.current\n            ?.setAttribute('aria-describedby', id);\n    }, [screenreaderOnly, id]);\n\n    /**\n     * Assume additional logic to\n     * bring-your-own HTML tag (BYOHTMLT)\n     * and force text node children.\n     */\n    return (\n        <div\n            className={ screenreaderOnly && 'visually-hidden' }\n            id={ id }>{ children }</div>\n    );  \n}\n\n// Usage\nfunction MyForm() {\n    const ref = useRef();\n    return (\n        <Text screenreaderOnly={ ref }>\n            Here are specific instructions for\n            the type of information this form\n            input is expecting to receive...\n        </Text>\n\n        <label for=\"example\">\n            Example\n        </label>\n        <input type=\"text\" id=\"example\" ref={ ref }>\n    )\n}\n```\n\nHowever you feel about using a `useEffect` to then use a DOM API to set an attribute that this component shouldn’t have control over is less important than the concept of connecting these two elements for accessibility purposes in an easy to use interface. It would be important to me that using `<Text screenreaderOnly>` *requires* the connection be maintained. It is too easy to accidentally rename `id`s in a vast composition of components causing accessibility wiring to break.\n\nAlso you can have your own naming convention to denote that the expected input is a `ref` to the element that you wish to describe.\n\nIt’s important to know that `aria-label`, `aria-labelledby` and `aria-describedby` are not valid on all elements. [The general gist is that these are meant for interactive elements or landmark elements.](https://www.tpgi.com/short-note-on-aria-label-aria-labelledby-and-aria-describedby/) This interface above *could* be enhanced to warn if the `ref` is attached to an element that is inappropriate but would need some more conditional logic to identify this.\n\n## Why `aria-describedby`\n\nThe benefits of using `aria-describedby` for screenreader only content is that first [it doesn’t replace existing labeling](https://www.aaron-gustafson.com/notebook/aria-quicktip-labelledby-vs-describedby/) (as `aria-labelledby` would); it is meant to accompany it. It also benefits by auto-translation technologies that may struggle finding `aria-label` content will [more easily find `aria-describedby` content](https://heydonworks.com/article/aria-label-is-a-xenophobe/) because it is written within a discoverable DOM node.\n\nCertainly `aria-describedby` isn’t *always* going to be the correct solution. I believe if you’ve done due dilligence in crafting a well prepared experience, with semantic elements and appropriate attribute usage, this approach is probably going to help provide additional context to visually-impared users [for complex interfaces](https://adrianroselli.com/2019/10/stop-giving-control-hints-to-screen-readers.html).\n\nKnow that if the content would also help visual users, you should absolutely consider putting the content inline with the composition and forego additional configuration complexity.\n\nAnd as always, reconsider the complexity of your experience overall, as you might be able to avoid cumbersome instructions for something simpler.",
    "version": "1.0"
  },
  "description": "Is this the exception to component-driven development?",
  "path": "/posts/screenreader-only",
  "publishedAt": "2024-04-27T00:00:00.000Z",
  "site": "https://blog.damato.design",
  "tags": [
    "accessibility",
    "css",
    "design"
  ],
  "textContent": "I am a big proponent of component-driven development, and don’t agree with the utility class method of styling. In component-driven development, you offer blackbox abstractions of common implementations. Meanwhile, the utility class method allows for more customization. In a systematic approach, we want our experiences to be consistent and therefore follow the same patterns and conventions. Distributing these blackboxes that align with guidelines by default makes a consistent experience easy to create and manage. Whereas, trying to learn and follow guidelines from other resources to implement piecemeal comes with misintereptations and other inconsistencies.\n\nHowever, in this work there has been one concept that I’ve stuggled to put into this component-driven ecosystem; screenreader only as it has traditionally existed as a class (eg., ) added to an otherwise benign element.\n\nAmongst the library\n\nThe purpose of screenreader only is to mark a section of an interface that is meant specifically for assistive technologies to pick up within the experience; invisible to sighted users. Here’s a common example:\n\nIn this example, sighted users will be able to see the path of the  in the shape of an ‘x’ with no other visual information. Non-sighted users who leverage assistive technology should receive “Close” from their tool and ignore the data set by the . There’s more about this composition and words about screenreader only versus  in this post by Chris Ferdinandi.\n\nMy gut reaction is that it would be odd to offer such a component that simply applies the styles required to make it hidden and for it to be offered as an exception to an otherwise utility-free ecosystem. However, I don’t like exceptions, I strive for consistent thoughtful systems.\n\nMy first thought is where a  would live amongst other components, if it is in fact a component itself. This is assuming that the library is vast and requires subsections that aim to direct visitors to the appropriate component through navigation. First I’d assume this might live with other “accessibility” components. However, this also assumes that folks are actively looking to include accessibility in their experiences; something that we can only dream of across an organization.\n\nFurther, we might consider accessibility as a quality of components, perhaps not a component itself. As I’m having difficulty thinking about other possible memebers of this family that would also be associated with the  component.\n\nMy next thought is that because it is a quality, perhaps it isn’t a component but a property on an existing component we set. Because we expect that the content of this conceptual  component to only ever be text, it might be safe to consider that it is a property of a text component.\n\nThe  component will be widely more popular than the possible  component, which will cause more folks to potentially visit its API and learn about this helpful feature. This being an opportunity to educate when its use is appropriate.\n\nIn doing the research for this article, I wondered if anyone had considered rethinking “Screenreader Only” as “ARIA only” as it is a shorter name with perhaps better marketing. I do worry that a person would believe that it is a valid ARIA attribute (it’s not) but I’m not the first to consider the idea for the purpose.\n\nWhen is it appropriate\n\nI did quite a bit of reading and research before writing this post. As I’m an advocate for accessibility, I don’t consider myself an expert and definitely have areas of improvement in my practice. I wanted to know when the concept of screenreader only was appropriate if at all.\n\nFor this topic, I highly recommend reading Scott O’Hara’s post called Inclusively Hidden.\n\nIn Scott’s post, he describes some alternatives to screenreader only; specifically one loophole in particular.\n\nBy attaching an  or  attribute to a focusable element, and setting the ARIA attribute’s value to the completely hidden element’s id, screen readers will announce the content of the completely hidden element.\n\nHere’s his example:\n\nIn this way, we still need to apply styles to the  element in order for it to disappear from view. But this also demonstrates how to connect that content to an interactive element for further context by using .\n\nFor completeness, here’s what Scott recommends as the styles for :\n\nI’m now imagining some sort of interface for when  is used on the  component to ensure it is connected to something.\n\nHowever you feel about using a  to then use a DOM API to set an attribute that this component shouldn’t have control over is less important than the concept of connecting these two elements for accessibility purposes in an easy to use interface. It would be important to me that using  requires the connection be maintained. It is too easy to accidentally rename s in a vast composition of components causing accessibility wiring to break.\n\nAlso you can have your own naming convention to denote that the expected input is a  to the element that you wish to describe.\n\nIt’s important to know that ,  and  are not valid on all elements. The general gist is that these are meant for interactive elements or landmark elements. This interface above could be enhanced to warn if the  is attached to an element that is inappropriate but would need some more conditional logic to identify this.\n\nWhy \n\nThe benefits of using  for screenreader only content is that first it doesn’t replace existing labeling (as  would); it is meant to accompany it. It also benefits by auto-translation technologies that may struggle finding  content will more easily find  content because it is written within a discoverable DOM node.\n\nCertainly  isn’t always going to be the correct solution. I believe if you’ve done due dilligence in crafting a well prepared experience, with semantic elements and appropriate attribute usage, this approach is probably going to help provide additional context to visually-impared users for complex interfaces.\n\nKnow that if the content would also help visual users, you should absolutely consider putting the content inline with the composition and forego additional configuration complexity.\n\nAnd as always, reconsider the complexity of your experience overall, as you might be able to avoid cumbersome instructions for something simpler.",
  "title": "Screenreader only",
  "updatedAt": "2026-06-13T16:19:08.469Z"
}