Skip to main content

Component Design Principles

Composable

Components and their corresponding component styles should prioritize composability. They should make no assumptions about their ancestors or their descendants.

Note: A notable exception is multi-component interface elements like menus or cards that rely on composing several components with interrelated concerns. Even then, those components' CSS selectors should keep CSS specificity as low as possible. They can leverage the inheritance of CSS variables to accomplish use cases that were previously only possible by chaining or nesting selectors.

Generic and reusable

Particle components should be generally useful in a variety of apps and interfaces. They should not be tied to one specific domain entity or a highly-specific use case.

With the exception of icons, the use of domain entity names (such as "snippet") is generally a red flag. That's an indication that the component is only intended for a specific interface, in which case it either doesn't belong in Particle or needs to be abstracted to be more generic and reusable.

Accessible

Particle is the backbone of our UIs, so in order for our interfaces to be accessible to the widest range of users, Particle components need to follow a11y best practices. At a minimum, that means that interactive elements need to be keyboard operable. They should also support HTML attributes to provide context to screen readers, such as titles, names (when applicable), and ARIA attributes (when necessary). A caution about ARIA: no ARIA is better than incorrect ARIA, so use those attributes with care.

note

This section can and should be fleshed out more.

Closed but configurable

To support various use cases and promote reusability, the behavior and appearance of Particle components can be configured in predetermined ways via props. But to provide stability and ease of maintenance, Particle components are intentionally built so they cannot be extended in unsupported ways. They expose a public API (props) and encapsulate private API (HTML elements, CSS classes, event handlers, and other Javascript behavior). As with any library, relying on or extending the private API is brittle and discouraged.

One important implementation detail stemming from this principle is that Particle components do not accept arbitrary CSS classes. A significant portion of the components' internal APIs is CSS. CSS properties not only provide the visual treatment, which is important for consistency, usability, and a11y, but in many cases provide critical behaviors, such as controlling visibility and pointer events.

Applying arbitrary classes creates the risk of 1) introducing unwanted or inconsistent design patterns, but more importantly 2) unintentionally breaking the internal behavior of the component.

Extending a component with unsupported CSS classes also creates a maintenance liability, as the private API of a component can change at any moment between minor and patch versions of the library. Care is taken when releasing new versions to ensure compatibility and anticipate, minimize, document, and provide solutions for breaking changes. But as Particle's usage grows (both in terms of scale and the number of engineers working with it) it becomes less and less feasible for the library's maintainers to know all of the ways it has been used or extended and more difficult to plan and execute changes for new releases.