A self-documenting design system specification for GraphQL.
query {
theme {
colors
boxShadows
a11yCombos {
contrast
backgroundColor
color
}
}
component(name: { eq: "Button" }) {
docs
propsTable {
key
defaultValue
description
type {
name
description
}
}
styledApi {
permutations
}
}
}
DesignQL provides a GraphQL based definition of a design system's primitives that can be queried and written to by all members of a team. This provides a powerful API for documenting components that still remains flexible for design system teams to have control of design and branding. It also provides a convenient mechanism for cloning for prototyping one-offs or experimenting with changes to the design system itself (theme, components, etc.).
When we build and document design systems we're often forced to reinvent the wheel with bespoke implementations. There are numerous design system and styleguide tools out there, but they often couple you to custom DSLs or lack flexibility. DesignQL seeks to provide users with a free and open API to build out design systems and document them with ease. Tables of props, playgrounds, and much more can be scaffolded out just from the source code and a colocated MDX file.
These days design and development for teams often have numerous render targets. Keeping them in sync can be difficult, especially when attempting to design generatively, access programmatically, or combine with tools lacking read/write APIs. Future goals of this project will include outputting a design system's primitives and tokens to React (styled-components/emotion/css modules), Vue, vanilla HTML/CSS (Tachyons, BEM, Tailwind).
We want to share it with the community for a few reasons:
- 👪 Improve upon it as a community
- ♻️ Encourage adoption with other design/development tools
- 🔧 Community-based implementations for other libraries/frameworks/etc
- 🔒 Avoid lock in for users
A design system typically consists of the same key parts:
- 🎨 theme
- 💅 branding
- 🗳️ components
- 📚 documentation
- 🏆 icons
DesignQL boils this down to a schema that can be shared amongst a team and their projects. It exposes a GraphQL API that can be used to document React code with many CSS-in-JS libraries and down the road export to other render targets like (Atomic CSS, React Native, Vue).
More importantly, it defines and provides an interface for programmatic access mentioned earlier.
DesignQL consists of multiple libraries that handle different types of source files.
Libraries:
- react-docgen
- styled-system
- MDX
- Gatsby
Here's an example Button component:
import styled from 'styled-components'
import { color, space } from 'styled-system'
import { variant, size } from './styled-functions'
/* @component */
export const Button = styled.button`
appearance: button;
${color}
${space}
${variant}
${size}
`
Button.displayName = 'Button'
Button.defaultProps = {
variant: 'primary',
size: 'md'
}
Button.propTypes = {
color: color.propTypes,
variant: variant.propTypes,
size: size.propTypes,
...space.propTypes
}
In order to keep the MVP as simple as possible, DesignQL currently expects a particular layout structure:
src/Button.js
src/Button.mdx
If there isn't a colocated MDX file it's no problem, DesignQL will do its best to parse out metadata.
- Source theme data from numerous locations
- CSS Stats
- Figma
- Sketch
- Framer
The DesignQL is defined by the following GraphQL schema:
The following types are used to define styling, styled functions, components, and theming.
The DesignSystem is the top level type that contains a theme, components, and docs.
type DesignSystem: {
theme: Theme!
branding: Branding!
components: [Components!]
}
Components are elements that have a name, props, styling, styled functions and documentation.
type Component: {
"""
Name of the component, Pascal cased
"""
name: String!
"""
Description of the component
"""
description: String
"""
HTML element type, also accepts react native primitive types
"""
element: String!
"""
Default props to apply to the component
"""
defaultProps: JSON
"""
Property types that the component accepts
"""
propTypes: JSON
"""
Property control API of the component, defined as a static property
"""
propertyControls: JSON
"""
List of StyledFunctions for the component
"""
StyledFunctions: [StyledFunction!]
"""
Additional metadata for the component, including information like status
"""
metadata: JSON
"""
Component specific documentation
"""
docs: String
"""
Location of the source file on disk
"""
srcPath: String!
"""
Location of the MDX file on disk
"""
docsPath: String
}
Themes are objects that define the values used by style props. Themes ensure consistent margin, padding, colors, font sizes, and other UI constants.
A design system can also define multiple themes. For example, a team might have a theme for apps and a theme for marketing pages.
type Theme: {
"""typography"""
fonts: JSON
fontSizes: JSON
fontWeights: JSON
lineHeights: JSON
letterSpacings: JSON
"""skins"""
colors: ColorMap
shadows: JSON
"""layout"""
space: JSON
widths: JSON
minWidths: JSON
maxWidths: JSON
heights: JSON
minHeights: JSON
maxHeights: JSON
"""borders"""
borders: JSON
radii: JSON
"""variants"""
variants: JSON
"""media queries"""
mediaQueries: [String!]
}
Branding consists of a brand's primary colors and its logos. Queries can be made that automatically return the proper logo type and its color based on parameters.
For example, if the background where the logo will be placed is a dark purple, the white logo is returned to ensure proper contrast.
type Branding {
"""
List of Logos
"""
logos: [Logo!]
"""
Branding specific colors
"""
colors: ColorMap!
"""
Documentation for branding
"""
docs: String
}
A styled function is based on Styled System. Styled functions have access to the theme, props, and optionally core Styled System functions. They return a JSON object.
type StyledFunction {
"""
Name for the function
"""
name: String!
"""
Component property
"""
prop: String!
"""
Name of core styled-system function
"""
styledSystem: String
"""
JSON property to set, defaults to prop
"""
JSONProp: String
"""
Convert numbers to px values
"""
toPx: Boolean
"""
Variant key (for example: buttons)
"""
variantKey: String
"""
Does this map to a theme key
"""
themeKey: String
"""
Documentation for the function
"""
docs: String
}
- ColorMap
- JSON
ColorMap consists of an object with nested objects, arrays, and strings. A color can be represented in hex, rgb, rgba, hsl, or a color name.
Values can only be strings.
Here's an example:
{
base: 'black',
bg: 'white',
blue: '#07c',
grays: [
'#999',
'#555',
'#111'
]
}
JSON properties can be an Int, Float, or String so we introduce a JSONProperty
type.
import { GraphQLJSON } from 'designql'
const typeDef = `
scalar JSON
`
const resolvers = {
JSON: GraphQLJSON
}
- John Otander
MIT