Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Accessibility-flavored React components make your design system delicious

C93a2f095a8dce6dbc3176db3e837db0?s=47 A11YChi
October 28, 2020

Accessibility-flavored React components make your design system delicious

Design systems are a popular way for teams to flavor their design and development workflow. However, an often-missing ingredient in many design systems is a focus on accessibility best practices — especially when component libraries are involved. In this talk, we’ll take a look at how you can mix some commonly-used components with the ingredients of accessibility. Pair this with best practices guidance in your documentation, and you’ll have the recipe for a delectably inclusive design system.

---
About the speaker

Kathleen McMahon (she/her) is a fullstack engineer with a design background. In other words, She really enjoys the front of the frontend, digging into new technologies, and talking about accessibility, React component libraries, design systems, and inclusive documentation. She is also a Color Module Specification Editor for the W3C Design Tokens Community Group. When not coding, designing, or speaking about things, Kathleen is the best Lanterne Rouge cyclocrosser you’ll ever meet.

Website: https://www.kathleenmcmahon.dev/
Twitter: https://twitter.com/resource11

C93a2f095a8dce6dbc3176db3e837db0?s=128

A11YChi

October 28, 2020
Tweet

Transcript

  1. Accessibility-flavored Kathleen McMahon @resource11 make your design system delicious React

    components
  2. https://noti.st/resource11 Slide deck posted after the talk @resource11

  3. @resource11 Twitter | Instagram | GitHub @resource11

  4. @resource11 Good grief, there’s an agenda... Why accessibility first? Design

    systems are a cookbook Design systems and React Icons Buttons Inputs Documentation @resource11
  5. Who are you, again? @resource11

  6. @resource11

  7. Cyclocross! @resource11

  8. None
  9. @resource11

  10. @resource11

  11. Dev Dinosaur

  12. @resource11

  13. @resource11

  14. @resource11

  15. @resource11

  16. @resource11

  17. @resource11 @resource11

  18. HTML + CSS + JS @resource11

  19. JavaScript Framework of the week @resource11

  20. None
  21. Dinosaurs are ALWAYS the hotness @resource11

  22. @resource11

  23. @resource11

  24. Great design systems combine team AND consumer experience

  25. @resource11 @resource11

  26. Business logic out, accessibility in First Priority @resource11

  27. Why accessibility first? @resource11

  28. Inclusive Design Persona Spectrum (CC BY-NC-SA 2.0) Motor Hearing Vision

    Cognitive Low bandwidth Language Sensory Our users are diverse
  29. WebAIM Million An accessibility analysis of the top 1,000,000 home

    pages February 2019 @resource11
  30. 97.8% of home pages had detectable WCAG 2 failures. @resource11

  31. 59% of 3.4 million form inputs were unlabeled @resource11

  32. 60.1% of the 1 million pages had ARIA present @resource11

  33. Web Content Accessibility Guidelines (WCAG) @resource11

  34. Imagine… accessibility baked into components. @resource11

  35. @resource11 Your Design system is a cookbook @resource11

  36. @resource11 Cookbooks have Personality @resource11

  37. @resource11

  38. @resource11

  39. @resource11

  40. @resource11

  41. @resource11

  42. @resource11

  43. @resource11

  44. @resource11

  45. Design Systems and React @resource11

  46. @resource11

  47. @resource11

  48. @resource11 React is a kitchen utensil CC BY-SA 2.0: Jeppestown

    utensil @resource11
  49. @resource11 You are the cook CC BY-SA 2.0: Jeppestown utensil

    @resource11
  50. @resource11 Empower with your design system CC BY-SA 2.0: Jeppestown

    utensil @resource11
  51. @resource11

  52. @resource11 Components are your tried and true recipes @resource11

  53. @resource11 WCAG is Your reference material @resource11

  54. @resource11 Component recipe @resource11

  55. @resource11 Use high-quality ingredients semantic HTML @resource11

  56. @resource11 Mix in seasonings ARIA …just a touch @resource11

  57. @resource11 Follow the directions documentation @resource11

  58. @resource11 Read helpful hints best practices @resource11

  59. @resource11 Icons @resource11

  60. @resource11 Icons Informative or decorative Informative icons need descriptive text

    Decorative icons need to be hidden from assistive technology @resource11
  61. @resource11 What does an icon mean, anyway? @resource11

  62. @resource11

  63. @resource11

  64. @resource11 Pair icons with text …when possible @resource11

  65. @resource11 Favorite Favorite

  66. @resource11 SVGs vs. Icon Fonts @resource11

  67. VoiceOver bugs make SVG sadness

  68. @resource11 Icon fonts to the rescue @resource11

  69. <span class="icon icon-email"></span> Icon font pattern @resource11

  70. <span class="root">
 <span class="icon icon-email" 
 aria-hidden="true"></span>
 <span class="visuallyHidden">email</span>
 </span>

    Accessible icon pattern @resource11
  71. @resource11 <span class="root">
 <span class="icon icon-email" 
 aria-hidden="true"></span>
 <span class="visuallyHidden">email</span>


    </span> Icon font .icon { color: currentColor; font-family: "ORM Icons"; } .icon-email::before {
 content: "\f12f";
 }
  72. <span class="root">
 <span class="icon icon-email" 
 aria-hidden="true"></span>
 <span class="visuallyHidden">email</span>
 </span>

    Hide icon font from screen readers .icon-email::before {
 content: "\f12f";
 } @resource11
  73. <span class="root">
 <span class="icon icon-email" 
 aria-hidden="true"></span>
 <span class="visuallyHidden">email</span>
 </span>

    Descriptive icon name @resource11
  74. @resource11 <span class="root">
 <span class="icon icon-email" 
 aria-hidden="true"></span>
 <span class="visuallyHidden">email</span>


    </span> Visually-hidden text .visuallyHidden {
 position: absolute;
 overflow: hidden;
 clip: rect(0 0 0 0);
 height: 1px;
 width: 1px;
 margin: -1px;
 padding: 0;
 border: 0;
 }
  75. @resource11 <span class="root">
 <span class="icon icon-email" 
 aria-hidden="true"></span>
 <span class="visuallyHidden">email</span>


    </span> Margin/padding support .root {
 display: inline-block;
 }
  76. <span class="root">
 <span class="icon icon-email" 
 aria-hidden="true"></span>
 <span class="visuallyHidden">email</span>
 </span>

    Spans all the way down @resource11
  77. Informative or decorative? <span class="root">
 <span class="icon icon-email" 
 aria-hidden="true"></span>


    <span class="visuallyHidden">email</span>
 </span> @resource11
  78. <span class="root">
 <span class="icon icon-email" 
 aria-hidden="true"></span>
 <span class="visuallyHidden">email</span>
 </span>

    Informative icons should announce @resource11
  79. Hide decorative icons from screen readers <span class=“root" aria-hidden="true">
 <span

    class="icon icon-email" 
 aria-hidden="true"></span>
 <span class="visuallyHidden">email</span>
 </span> @resource11
  80. export const Icon = props => { 
 return (


    <span class="root">
 <span class="icon icon-email” aria-hidden=”true” />
 <span class="visuallyHidden">email</span>
 </span>
 );
 } 
 export default Icon; HTML syntax React functional component @resource11
  81. export const Icon = props => { 
 return (


    <span className="root">
 <span className="icon icon-email” aria-hidden={true} />
 <span className="visuallyHidden">email</span>
 </span>
 );
 } 
 export default Icon; class 㱺 className Close empty span “true” 㱺 {true} @resource11
  82. JSX syntax export const Icon = props => { 


    return (
 <span className="root">
 <span className="icon icon-email” aria-hidden={true} />
 <span className="visuallyHidden">email</span>
 </span>
 );
 } 
 export default Icon; @resource11
  83. export const Icon = props => {
 const { iconHidden,

    iconName, iconTitle } = this.props;
 const icon = Icons[iconName];
 if (!icon) return null;
 
 return (
 <span className="root" aria-hidden={iconHidden ? true : null}>
 <span
 className={`icon icon-${iconName}`} aria-hidden={true}
 />
 <span className="visuallyHidden">
 {iconTitle || iconName}
 </span>
 </span>
 );
 }
 export default Icon; Support incoming props, add guardrails @resource11
  84. Guardrails @resource11

  85. export const Icon = props => {
 const { iconHidden,

    iconName, iconTitle } = this.props;
 const icon = Icons[iconName];
 if (!icon) return null;
 
 return (
 <span className="root" aria-hidden={iconHidden ? true : null}>
 <span
 className={`icon icon-${iconName}`} aria-hidden={true}
 />
 <span className="visuallyHidden">
 {iconTitle || iconName}
 </span>
 </span>
 );
 }
 export default Icon; Icon naming guardrails @resource11
  86. export const Icon = props => {
 const { iconHidden,

    iconName, iconTitle } = this.props;
 const icon = Icons[iconName];
 if (!icon) return null;
 
 return (
 <span className="root" aria-hidden={iconHidden ? true : null}>
 <span
 className={`icon icon-${iconName}`} aria-hidden={true}
 />
 <span className="visuallyHidden">
 {iconTitle || iconName}
 </span>
 </span>
 );
 }
 export default Icon; Icon description guardrails @resource11
  87. export const Icon = props => {
 const { iconHidden,

    iconName, iconTitle } = this.props;
 const icon = Icons[iconName];
 if (!icon) return null;
 
 return (
 <span className="root" aria-hidden={iconHidden ? true : null}>
 <span
 className={`icon icon-${iconName}`} aria-hidden={true}
 />
 <span className="visuallyHidden">
 {iconTitle || iconName}
 </span>
 </span>
 );
 }
 export default Icon; Icon Hiding guardrails @resource11
  88. export const Icon = props => {
 const { iconHidden,

    iconName, iconTitle } = this.props;
 const icon = Icons[iconName];
 if (!icon) return null;
 
 return (
 <span className="root" aria-hidden={iconHidden ? true : null}>
 <span
 className={`icon icon-${iconName}`} aria-hidden={true}
 />
 <span className="visuallyHidden">
 {iconTitle || iconName}
 </span>
 </span>
 );
 }
 export default Icon; Icon Hiding guardrails @resource11
  89. @resource11 …but SVGs! @resource11

  90. @resource11

  91. @resource11

  92. @resource11

  93. <FontAwesomeIcon icon=“coffee” /> @resource11

  94. <svg data-icon=“coffee” aria-hidden=“true” focusable=“false” /> <path>…</path> </svg> @resource11

  95. <FontAwesomeIcon icon=“coffee” ariaLabel=“beverage” /> @resource11

  96. <FontAwesomeIcon icon=“coffee” ariaLabel=“beverage” /> @resource11

  97. <svg data-icon=“coffee” aria-hidden=“true” focusable=“false” aria-label=“beverage” /> <path>…</path> </svg> @resource11

  98. <svg data-icon=“coffee” aria-hidden=“true” focusable=“false” aria-label=“beverage” /> <path>…</path> </svg> @resource11 aria-label

    will not announce aria-hidden hides from screen reader
  99. export const Icon = props => {
 const { iconHidden,

    iconName, iconTitle } = this.props;
 
 return (
 <span className=“root” aria-hidden={iconHidden ? true : null}>
 <span
 className={`icon icon-${iconName}`} aria-hidden={true}
 />
 <span className="visuallyHidden">
 {iconTitle || iconName}
 </span>
 </span>
 );
 }
 export default Icon; @resource11 Swap out font-based className
  100. export const Icon = props => {
 const { iconHidden,

    iconName, iconTitle } = this.props;
 
 return (
 <span className="root" aria-hidden={iconHidden ? true : null}>
 <FontAwesomeIcon
 icon={iconName}
 />
 <span className="visuallyHidden">
 {iconTitle || iconName}
 </span>
 </span>
 );
 }
 export default Icon; @resource11 Swap in FontAwesomeIcon
  101. export const Icon = props => {
 const { iconHidden,

    iconName, iconTitle } = this.props;
 
 return (
 <span className="root" aria-hidden={iconHidden ? true : null}>
 <FontAwesomeIcon
 icon={iconName}
 />
 <span className="visuallyHidden">
 {iconTitle || iconName}
 </span>
 </span>
 );
 }
 export default Icon; Informative icon naming supported @resource11
  102. @resource11 Buttons @resource11

  103. @resource11 Buttons Perform an action on the page Should look

    and act like a button Screen reader and keyboard functionality for free @resource11
  104. Button <button class="root">
 Send an email
 </button> @resource11

  105. <button class="root" aria-label="Read more about Dinosaurs">
 Read more
 </button> Button

    Sprinkle some ARIA @resource11
  106. <button class="root" aria-label=“Read more about dinosaurs">
 Read more
 </button> Button

    Sprinkle some ARIA @resource11 Button text and aria label start with same words
  107. <button class="root" aria-label=“Read more about dinosaurs">
 Read more
 </button> Button

    Sprinkle some ARIA @resource11 Button text and aria label start with same words
  108. <button className="root" aria-label="Read about Dinosaurs">
 Read More
 </button> Button @resource11

  109. <button className="root" aria-label="Read about Dinosaurs>
 {children}
 <Icon
 iconName={iconName}
 iconHidden={true}
 />


    </button> Add icon support @resource11
  110. <button className="root" aria-label="Read about Dinosaurs 
 onClick={onClick} disabled={disabled ? true

    : null}>
 <span className="btnContentWrap">
 {children}
 <Icon
 iconName={iconName}
 iconHidden={true}
 />
 </span>
 </button> Wrap contents in span @resource11
  111. export const Button = props => {
 const { ariaLabel,

    children, disabled, iconName, onClick.}.= this.props;
 
 return (
 <button className="root" aria-label={ariaLabel} 
 onClick={onClick} disabled={disabled ? true : null}>
 <span className="btnContentWrap">
 {children}
 {iconName && (
 <Icon
 iconName={iconName}
 iconHidden={true}
 />
 )}
 </span>
 </button>
 );
 } Add props, click handler & disabled button support @resource11
  112. export const Button = props => {
 const { ariaLabel,

    children, disabled, iconName, onClick.}.= this.props;
 
 return (
 <button className="root" aria-label={ariaLabel} 
 onClick={onClick} disabled={disabled ? true : null}>
 <span className="btnContentWrap">
 {children}
 {iconName && (
 <Icon
 iconName={iconName}
 iconHidden={true}
 />
 )}
 </span>
 </button>
 );
 } No iconName? No icon rendered Add guardrails @resource11
  113. @resource11 @resource11 Inputs

  114. @resource11 Inputs need labels and error messages Labeled inputs give

    all users more context @resource11
  115. @resource11 Placeholders are NOT labels Avoid using placeholders instead of

    labels, users will lose context Hard to style across browsers Placeholders aren’t auto translated @resource11
  116. @resource11 Avoid Horizontal Scrolling Max input width: 80 characters Keep

    labels stacked vertically in close proximity Labels above input, errors below input @resource11
  117. <div className="root"> {label && ( <label htmlFor={id} className="inputLabel">{label}</label> {iconName &&

    ( <Icon iconName={iconName} iconHidden={true} /> )} <input className={inputClasses} id={id} name={id} type={type} value={value} disabled={disabled ? true : null} onChange={onChange} onKeyPress={onKeyPress} aria-describedby={invalid && error ? `error-${id}` : null} aria-invalid={invalid ? true : null} aria-required={required ? true : null} /> } {invalid && error && ( <div className="errorWrapper"> <Icon iconName="warning-fill" iconHidden={true} /> <span id={`error-${id}`} className="errorTxt" aria-live="polite" > {error} </span> </div> } </div> @resource11
  118. @resource11 <div className="root"> {label && ( <label htmlFor={id} className="inputLabel">{label}</label> {iconName

    && ( <Icon iconName={iconName} iconHidden={true} /> )} <input className={inputClasses} id={id} name={id} type={type} value={value} disabled={disabled ? true : null} onChange={onChange} onKeyPress={onKeyPress} aria-describedby={invalid && error ? `error-${id}` : null} aria-invalid={invalid ? true : null} aria-required={required ? true : null} /> } {invalid && error && ( <div className="errorWrapper"> <Icon iconName="warning-fill" iconHidden={true} /> <span id={`error-${id}`} className="errorTxt" aria-live="polite" > {error} </span> </div> } </div> <div class=“root”> <label for="inputFoo" class="inputLabel"> First name </label> <input class="inputClasses" id=“inputFoo"
 name="inputFoo"
 type="text" /> <span id=“errorFoo" class="errorTxt"> Whoops! Error. </span> </div> Semantic HTML
  119. <div className="root"> {label && ( <label htmlFor={id} className="inputLabel">{label}</label> {iconName &&

    ( <Icon iconName={iconName} iconHidden={true} /> )} <input className={inputClasses} id={id} name={id} type={type} value={value} disabled={disabled ? true : null} onChange={onChange} onKeyPress={onKeyPress} aria-describedby={invalid && error ? `error-${id}` : null} aria-invalid={invalid ? true : null} aria-required={required ? true : null} /> } {invalid && error && ( <div className="errorWrapper"> <Icon iconName="warning-fill" iconHidden={true} /> <span id={`error-${id}`} className="errorTxt" aria-live="polite" > {error} </span> </div> } </div> @resource11 Labels and error messages <div class=“root”> <label for="inputFoo" class="inputLabel"> First name </label> <input class="inputClasses" id=“inputFoo"
 name="inputFoo"
 type="text" /> <span id=“errorFoo" class="errorTxt"> Whoops! Error. </span> </div>
  120. <div className="root"> {label && ( <label htmlFor={id} className="inputLabel">{label}</label> {iconName &&

    ( <Icon iconName={iconName} iconHidden={true} /> )} <input className={inputClasses} id={id} name={id} type={type} value={value} disabled={disabled ? true : null} onChange={onChange} onKeyPress={onKeyPress} aria-describedby={invalid && error ? `error-${id}` : null} aria-invalid={invalid ? true : null} aria-required={required ? true : null} /> } {invalid && error && ( <div className="errorWrapper"> <Icon iconName="warning-fill" iconHidden={true} /> <span id={`error-${id}`} className="errorTxt" aria-live="polite" > {error} </span> </div> } </div> @resource11 <div className=“root”> <label htmlFor="inputFoo" className="inputLabel"> First name </label> <input className="inputClasses" id="inputFoo"
 name="inputFoo"
 type="text" /> <span id=“errorFoo" className="errorTxt"> Whoops! Error. </span> </div> Associate label with input
  121. @resource11 <div className="root"> {label && ( <label htmlFor={id} className="inputLabel">{label}</label> {iconName

    && ( <Icon iconName={iconName} iconHidden={true} /> )} <input className={inputClasses} id={id} name={id} type={type} value={value} disabled={disabled ? true : null} onChange={onChange} onKeyPress={onKeyPress} aria-describedby={invalid && error ? `error-${id}` : null} aria-invalid={invalid ? true : null} aria-required={required ? true : null} /> } {invalid && error && ( <div className="errorWrapper"> <Icon iconName="warning-fill" iconHidden={true} /> <span id={`error-${id}`} className="errorTxt" aria-live="polite" > {error} </span> </div> } </div> <div className="root"> <label htmlFor="inputFoo" className="inputLabel"> First name </label> <input className="inputClasses" id=“inputFoo" name=“inputFoo" type="text" aria-describedby=“errorFoo" aria-invalid="true" aria-required="true" /> <span id="errorFoo" className="errorTxt"> Whoops! Error. </span> </div> Sprinkle some ARIA
  122. <div className="root"> {label && ( <label htmlFor={id} className="inputLabel">{label}</label> {iconName &&

    ( <Icon iconName={iconName} iconHidden={true} /> )} <input className={inputClasses} id={id} name={id} type={type} value={value} disabled={disabled ? true : null} onChange={onChange} onKeyPress={onKeyPress} aria-describedby={invalid && error ? `error-${id}` : null} aria-invalid={invalid ? true : null} aria-required={required ? true : null} /> } {invalid && error && ( <div className="errorWrapper"> <Icon iconName="warning-fill" iconHidden={true} /> <span id={`error-${id}`} className="errorTxt" aria-live="polite" > {error} </span> </div> } </div> @resource11 <div className="root"> <label htmlFor="inputFoo" className="inputLabel"> First name </label> <input className="inputClasses" id="inputFoo"
 name="inputFoo"
 type="text" aria-describedby="errorFoo" aria-invalid="true" aria-required="true" /> <span id="errorFoo" className="errorTxt" aria-live="polite"> Whoops! Error. </span> </div>
  123. @resource11 <div className="root"> {label && ( <label htmlFor={id} className="inputLabel">{label}</label> {iconName

    && ( <Icon iconName={iconName} iconHidden={true} /> )} <input className={inputClasses} id={id} name={id} type={type} value={value} disabled={disabled ? true : null} onChange={onChange} onKeyPress={onKeyPress} aria-describedby={invalid && error ? `error-${id}` : null} aria-invalid={invalid ? true : null} aria-required={required ? true : null} /> } {invalid && error && ( <div className="errorWrapper"> <Icon iconName="warning-fill" iconHidden={true} /> <span id={`error-${id}`} className="errorTxt" aria-live="polite" > {error} </span> </div> } </div> <div className="root"> <label htmlFor={id} className="inputLabel"> {label} </label> <input className={inputClasses} id={id} name={id} type={type} value={value} disabled={disabled ? true : null} onChange={onChange} onKeyPress={onKeyPress} aria-describedby={invalid && error ? `error-${id}` : null} aria-invalid={invalid ? true : null} aria-required={required ? true : null} /> <span id={`error-${id}`} className="errorTxt" aria-live="polite" > {error} </span> </div> disabled and synthetic event support and true/null handling
  124. @resource11 <div className="root"> {label && ( <label htmlFor={id} className="inputLabel">{label}</label> {iconName

    && ( <Icon iconName={iconName} iconHidden={true} /> )} <input className={inputClasses} id={id} name={id} type={type} value={value} disabled={disabled ? true : null} onChange={onChange} onKeyPress={onKeyPress} aria-describedby={invalid && error ? `error-${id}` : null} aria-invalid={invalid ? true : null} aria-required={required ? true : null} /> } {invalid && error && ( <div className="errorWrapper"> <Icon iconName="warning-fill" iconHidden={true} /> <span id={`error-${id}`} className="errorTxt" aria-live="polite" > {error} </span> </div> } </div> {label && ( <label htmlFor={id} className="inputLabel"> {label} </label> {iconName && ( <Icon iconName={iconName} iconHidden={iconHidden} title={iconTitle} /> )} <input className={inputClasses} id={id} name={id} type={type} value={value} disabled={disabled ? true : null} onChange={onChange} onKeyPress={onKeyPress} aria-describedby={invalid && error ? `error-${id}` : null} aria-invalid={invalid ? true : null} aria-required={required ? true : null}
 /> )} Add guardrails
  125. @resource11 <div className="root"> {label && ( <label htmlFor={id} className="inputLabel">{label}</label> {iconName

    && ( <Icon iconName={iconName} iconHidden={true} /> )} <input className={inputClasses} id={id} name={id} type={type} value={value} disabled={disabled ? true : null} onChange={onChange} onKeyPress={onKeyPress} aria-describedby={invalid && error ? `error-${id}` : null} aria-invalid={invalid ? true : null} aria-required={required ? true : null} /> } {invalid && error && ( <div className="errorWrapper"> <Icon iconName="warning-fill" iconHidden={true} /> <span id={`error-${id}`} className="errorTxt" aria-live="polite" > {error} </span> </div> } </div> {invalid &&
 error && (
 <div className="errorWrapper">
 <Icon iconName="warning-fill"
 iconHidden={true} />
 <span
 id={`error-${id}`}
 className="errorTxt"
 aria-live="polite"
 >
 {error}
 </span>
 </div>
 )} Add guardrails
  126. @resource11 Disclosure Widgets @resource11

  127. @resource11 Disclosure Widgets Flexible pattern Keyboard and mouse operable Shared

    base functionality @resource11
  128. @resource11 Menus & Toggle Tips @resource11

  129. @resource11 Tooltips are NOT Toggle Tips @resource11

  130. @resource11 Tooltips can be problematic @resource11

  131. @resource11 Primary keyboard interactions Space bar/Enter key Escape key Mouse

    clicks @resource11
  132. @resource11 Targeted focus management @resource11

  133. @resource11 Disclosure Widgets Demo @resource11

  134. @resource11 Document, document, document @resource11

  135. @resource11 + @resource11

  136. @resource11 @resource11

  137. @resource11 @resource11

  138. @resource11 @resource11

  139. @resource11

  140. Helpful hints Informative Icon @resource11

  141. Helpful hints Decorative Icon @resource11

  142. Helpful hints Prop tables @resource11

  143. Helpful hints Component dos/don’ts @resource11

  144. @resource11 Dedicate a page to accessibility resources @resource11

  145. Wrap-up @resource11

  146. Inclusive Design Persona Spectrum (CC BY-NC-SA 2.0) Motor Hearing Vision

    Cognitive Low bandwidth Language Sensory Our users are diverse
  147. @resource11 Your Design system is a cookbook @resource11

  148. @resource11 Cookbooks have Personality @resource11

  149. @resource11 React is a kitchen utensil CC BY-SA 2.0: Jeppestown

    utensil @resource11
  150. @resource11 You are the cook CC BY-SA 2.0: Jeppestown utensil

    @resource11
  151. @resource11 Components are your tried and true recipes @resource11

  152. @resource11 WCAG is Your reference material @resource11

  153. @resource11 Document, document, document @resource11

  154. Dinosaurs are ALWAYS the hotness @resource11

  155. Thank you. @resource11

  156. https://noti.st/resource11 Slide deck posted after the talk @resource11 Twitter |

    Instagram | GitHub @resource11