A spec proposal for a common spacing API among components of a design system.
A design system combines several aspects of an user interface and sets the rules
for their usage. This includes e.g. colors, fonts and spaces.
Traditionally in web development with CSS, spaces are mostly applied using the
padding
(inner spacing) and margin
(outer spacing) properties. This forms
something like a "low level API" to spacing.
Coming from a more component based approach of composing interfaces, the components
come with a high level API for a variety of purposes, sometimes called "props" or
"attributes".
It is up to the author of the library to choose the level of their exposure. But it seems
reasonable not to expose the whole CSS styling API in order to prevent abuse or
unexpected behavior.
This said you may want to offer some kind of high level API in the shape a of configuration
through props.
Similar to the CSS box model this spec provides two kinds of spacings: "outer spaces" as a way to set the margin around a component and "inner spaces" for the padding equivalent. While the former will be discussed in detail, the latter mostly adapts the same principles and will probably get used less commonly.
- <spacing>
- The alias of the spacing as defined by the design system.
- auto
- The browser selects a suitable spacing to use. For example, in certain cases this value can be used to center an element.
As known from margin
and padding
CSS properties, this spec offers a shorthand notation: outerSpace
.
[ <spacing> | auto ]{1,4}
Variant | Description |
---|---|
[all] |
Apply to all four sides |
[block, inline] |
vertical | horizontal |
[block-start, inline, block-end] |
top | horizontal | bottom |
[block-start, inline-end, block-end, inline-start] |
top | right | bottom | left |
Single direction properties are offered as well:
outerSpaceBlockStart
outerSpaceBlockEnd
outerSpaceInlineStart
outerSpaceInlineEnd
<spacing> | auto
ℹ For more details on logical properties see this article on MDN.
These examples show a potential implementation using CSS Custom Properties and a mapping to CSS logical properties for ReactJS components
import { MyComponent, Spaces } from '@scope/design-system';
<MyComponent outerSpace={[Spaces.M]}>
/** Resulting styles
* margin: var(--space--m);
*/
import { MyComponent, Spaces } from '@scope/design-system';
<MyComponent outerSpace={[Spaces.M, Spaces.S, Spaces.XL]}>
/** Resulting styles
* margin: var(--space--m) var(--space-s) var(--space--xl);
*
* @supports(margin-block-end: 0) {
* margin-block-start: var(--space--m);
* margin-block-end: var(--space--xl);
* margin-inline-start: var(--space--s);
* margin-inline-end: var(--space--s);
* }
*/
import { MyComponent, Spaces } from '@scope/design-system';
<MyComponent outerSpaceBlockEnd={Spaces.XL}>
/** Resulting styles
* margin-bottom: var(--space--xl);
*
* @supports(margin-block-end: 0) {
* margin-block-end: var(--space--xl);
* }
*/
Some design systems use adaptive values corresponding to the current media (aka media queries). By using CSS Custom Properties, this can be archived fairly simple:
:root {
--space--s: 4px;
--space--m: 8px;
--space--xl: 16px;
@media (min-width: 640px;) {
--space--s: 6px;
--space--m: 12px;
--space--xl: 24px;
}
}
At the same time you might not want all the spaces to adapt, so an extension to the above spec could be to introduce distinct fixed and adaptive properties:
import { MyComponent, Spaces } from '@scope/design-system';
<MyComponent
outerSpaceBlockStartFixed={Spaces.M}
outerSpaceBlockEnd={Spaces.XL}
/>
/** Resulting styles
* margin-top: 8px;
* margin-bottom: var(--space--xl);
*
* @supports(margin-block-end: 0) {
* margin-block-start: 8px;
* margin-block-end: var(--space--xl);
* }
*/