An incomplete list of the principles guiding decisions around API and implementation details in the Design-System.
Eg. For component props which map directly to css properties, just use the same name. Shortening flexGrow
to grow
makes it harder to understand what that prop does.
This is an idea that comes from Perl and can be used when thinking about how to define an API.
A simple example of this is the LinkList
component.
In it’s simplest and most easy to use form, the component takes a links
prop which is a list of the href
and text label
for each link.
import { LinkList } from '@ag.ds-next/link-list';
<LinkList
links={[
{ href: '/', label: 'Home' },
{ href: '/about', label: 'About' },
]}
/>;
If you wanted however to add an Icon to one or more of the links, this can be easily achieved by passing a react node as the label
instead of a string.
import { LinkList } from '@ag.ds-next/link-list';
<LinkList
links={[
{
href: '/',
label: (
<Box>
<HouseIcon /> Home
</Box>
),
},
{
href: '/about',
label: (
<Box>
<QuestionIcon /> About
</Box>
),
},
]}
/>;
If you wanted to do something more complex you can pick and choose the parts of LinkList
which are useful to you and replace anything you need to.
// In this example, we create a LinkList component which can highlight external links
import { LinkListGroup, LinkListItem } from '@ag.ds-next/link-list';
const isExternal = (href: string) => href.startsWith('http');
const CustomLinkList = ({ links, ..props }) => (
<LinkListGroup {...props}>
{links.map(({ label, ...props }, index) => (
<LinkListItem key={index}>
{label} {isExternal(href) ? '[^]' : ''}
</LinkListItem>
))}
</LinkListGroup>
);
So components which are a composition of several other components (like LinkList
) should expose their parts in addition to the main component to enable recomposing the parts in a different way. This lets us maintain a simple API while enabling more complex use cases.
It is fully expected that almost every design-system component will depend on core
and box
but beyond that, we should try to limit cross dependencies as much as possible.
It’s tempting to look, for example, at the
SideNavigation
component, see that in mobile it collapses to an accordion and then try to use theAccordion
inside ofSideNavigation
.
Going down this path is fraught.
- While there are certainly similarities in the look and functionality of these components they are fundamentally different. The
Accordion
is always an accordion. Open or closed. Nothing more. TheSideNavigation
however could change at runtime (on resize or device rotation) from a collapsible accordion-like component to one with a fixed height, locked open and then back again. This is a feature of theSideNavigation
and not something theAccordion
should be aware of or have to support. - While the relationship from
SideNavigation
toAccordion
may be easy to see, there is no indication from within theAccordion
that this dependency exists. This can leads to changes in theAccordion
causing issues inSideNavigation
with no good way to expose this dependency.
A better choice here is to take the parts of Accordion
which are common / reusable and extract them to a more generic component or into core
as a utility. If this is too hard, copy paste the code to the new component. Duplication is better than dependency here.
This Design-System will likely be adopted either only partially or incrementally. For this reason it is important that we avoid polluting global namespaces and scopes in CSS and JavaScript.
This is why the neither core
or prose
apply a default fontFamily
or color
and why the global reset is minimal and optional. For each component in the design system we need to consider whether it is appropriate for the component to apply styling to it’s children.
In the context of LinkList
, it makes sense to apply styles to the child a
tags (color
, textDecoration
, fontFamily
etc.). That is the purpose of the component.
In the case of Box
or Stack
, unless the user has specified a property we should not apply anything that effects the component’s children.
When choosing defaults it’s important to consider that some css properties will be inherited by child elements while others will not.
Eg, setting color on a Box
will apply that color to child text nodes. Setting width
will only change the width of the Box
component itself.
For new components or features, use the following check list to ensure you have everything in place.
-
The component is available for use in playroom
docs/playroom/components.js
-
The component is available for use in
live
blocks in the Docs site. `` -
Stories exist for all color variants eg. light and dark theme containers (if relevant).
-
Consider accessibility (a11y)
- What does Gold do?
- Use the appropriate html elements.
- Aria roles and attributes.
- Focus styles and keyboard nav.
Can you answer the following questions:
If I couldn’t see the screen how would I know:
- what this is?
- what this does?
- what just happened?