design systems for Big Enterprise ™ • Built several others for smaller companies • Distilled that knowledge in Bento, a general purpose design system for the web
design at scale by reducing redundancy while creating a shared language and visual consistency across different pages and channels. -- Nielsen Norman Group
build time (no runtime overhead) • Similar to CSS modules in spirit • Originally created by Seek for their own DS (Braid) • Successor of treat (https:/ /seek-oss.github.io/treat/)
Fewer moving parts, CSS integrates well with any stack • No runtime overhead • Seems more future proof, for example when it comes to SSR (see https:/ /github.com/reactwg/react-18/discussions/108)
(can keyboard and screen reader users jump around the content effectively?) • Link purpose <!-- Bad --> Go to Google by clicking <a href="google.com">this link</a> <!-- Good --> Click here to <a href="google.com">go to Google</a>
Ensuring text is readable wrt its background and size • Operating via mouse, keyboard, touch, screen reader • Ensuring the interactions work across difference devices
Ensuring the focus is always visible • Ensuring modal content does not let the focus escape • Form interactions • Ensuring labels/errors are linked to fields • Ensuring error state is not only a color
icon="{IconPencil}" /> // ^^^^^^^^ // Property 'label' is missing // ✅ <IconButton size="{16}" icon="{IconPencil}" label="Edit user" /> Here label is used for screen readers, but it's also useful for mouse users (hover tooltip).
focus of its descendants. This is crucial to implement focus traps (e.g. modals) correctly. <FocusScope contain restoreFocus> <!-- Modal content goes here --> </FocusScope>
create a number field supporting multiple languages and locale? Yeah, I have PTSD too... useNumberField to the rescue! Why not <input type="number">? Let's take a look
percentages, currency values, and units • Support for the Latin, Arabic, and Han positional decimal numbering systems in over 30 locales • Automatically detects the numbering system used and supports parsing numbers not in the default numbering system for the locale • Support for multiple currency formats including symbol, code, and name in standard or accounting notation
only valid numeric input according to the locale and numbering system is accepted • Handles composed input from input method editors, e.g. Pinyin • Automatically selects an appropriate software keyboard for mobile according to the current platform and allowed values • Supports rounding to a configurable number of fraction digits
and maximum, and snapping to a step value • Support for stepper buttons and arrow keys to increment and decrement the value according to the step value • Supports pressing and holding the stepper buttons to continuously increment or decrement • Handles floating point rounding errors when incrementing, decrementing, and snapping to step
the value • Exposed to assistive technology as a text field with a custom localized role description using ARIA • Follows the spinbutton ARIA pattern • Works around bugs in VoiceOver with the spinbutton role • Uses an ARIA live region to ensure that value changes are announced • Support for description and error message help text linked to the input via ARIA
a code change will affect the UI. This may or may not be true. • Code changes may not affect the UI • The snapshot may not catch UI changes that indirectly affect other components Can we do better?
DS library manifest as visual bugs. Other bugs can arise, but this is are by far the most common ones. You want a lot of visual tests, think of it as the base of the pyramid.
also support interaction testing • Write tests for stories using Storybooks' play function • It uses the testing-library API • Chromatic runs them automatically and reports failures alongside visual tests
const label: LocalizedString; declare function giveMeAString(s: string); declare function giveMeALocalizedString(s: LocalizedString); giveMeAString(normalString); // OK giveMeAString(label); // OK giveMeALocalizedString(label); // OK giveMeALocalizedString(normalString); // Error
casting bad? In general, yes. In this case, it's fine if confined to a single function. In practice you wrap the localization function of a library like react- i18next or react-intl, to change the return type to LocalizedString instead of string.
I'm a library and I don't want to force this mechanism on my users? Ideal scenario: • the library accepts string by default • the consume can opt-in into stricter type-safety via LocalizedString
empty interface meant to be "merged": export interface TypeOverrides {} we then define the "base" types: interface BaseTypes { LocalizedString: string; }
import { O } from "ts-toolbelt"; type ConfiguredTypes = O.Overwrite<BaseTypes, TypeOverrides>; // This is the type we use in our library export type LocalizedString = BaseTypes["LocalizedString"] & ConfiguredTypes["LocalizedString"]; // Our beloved stricter type export type StrictLocalizedString = string & { readonly __brand: unique symbol; };