The Design System and supporting website for Westpac GEL





GitHub Stars



Last Commit

11d ago








Type Definitions





GEL CircleCI

For the docs for the design system please go to


This repo consists of the following parts:

  • /brands/* and /components/* The react design system components publish to npm
  • /website/* The website CMS and template (see the Website README for details)
  • /helpers/* Some helper scripts
  • /nginx/* The nginx config for the server


See also the Website README.


To run this repo locally please use yarn. This repo is a monorepo. Learn more about monorepos at https://monorepo.guide/.

cd path/to/repo

This will install all dependencies for all packages in this monorepo.

👉 The file structure of this monorepo
├── README.md
├── package.json
├── yarn.lock
├── helper/
│   ├── .component-template/        # the starter files for when a new component is created via cli
│   │
│   ├── example/
│   │   ├── components/             # an assortment of components helping us build the example pages
│   │   ├── _utils.js               # shared logic
│   │   ├── docs.js                 # entry file for `yarn docs` task
│   │   ├── docs.webpack.config.js  # dynamic webpack config to run the `yarn docs` task
│   │   ├── index.html              # the index.html file as entry point
│   │   ├── start.js                # entry file for `yarn start` task
│   │   └── start.webpack.config.js # dynamic webpack config to run the `yarn start` task
│   │
│   ├── public/                     # files in this folder will be moved into the docs/ folder
│   │
│   ├── tests/                      # test specific files for reuse between component tests
│   │
│   ├── transformer/                # the transfomer files to convert tokens into platform data
│   │   ├── _utils.js               # shared logic
│   │   └── web.js                  # transforms tokens to web
│   │
│   ├── buildExports.js             # helps cypress testing of each component
│   ├── cli.js                      # helper file for cli like adding a new module
│   ├── ds-info.js                  # helper file to generate the GEL.json
│   └── tester.js                   # helps cypress testing of each component
├── components/                     # all ds components that are published
│   ├── component1/                 # more on the structure of components below
│   ├── component2/
│   └── component3/
├── brands/                         # all brand components
│   ├── BOM/
│   │   ├── dist/                   # distribution files (build artifact)
│   │   ├── overrides/              # all overrides files specific to this brand
│   │   ├── src/                    # our source files
│   │   ├── tokens/                 # token files
│   │   ├── CHANGELOG.md
│   │   ├── LICENSE
│   │   ├── package.json
│   │   └── README.md
│   ├── BSA/
│   │   └── etc
│   └── WBC/
│       └── etc
├── website/                        # all files related to the CMS and website
└── docs/                           # the static files for the documentation (build artifact)
👉 npm scripts
yarninstall all dependencies
yarn nukeremoves all node_modules for fresh start
yarn freshremoves all node_modules and reinstalls them
yarn buildbuild all dist folders for production
yarn build:devbuild all dist for local consumption
yarn docsbuild docs for all components and run server
yarn docs:buildbuild docs for all components to ./docs/ folder
yarn new [package-name]create a new specified empty component
yarn dev [package-name]start the example server of a component
yarn testruns tests
yarn formatruns prettier to format all code
yarn deploy:stagingdeploys the site to staging from the staging branch
yarn deploy:livedeploys the site to live from the master branch

See the Website README for details on it's deployment.

Design System

The design system components are spread between two folders:

├── brands/     # The brand components
└── components/ # The design system components including core

There are two different ways you can run the components locally:

  1. Component build
  2. Docs build

Some high level decisions

  • All components use named exports as the default, no default exports
  • All brands components will have a default export containing the "tokens" objects in addition to the named exports of each.
  • Fonts can't be shipped with npm so the tokens only define the css declarations for the fonts
  • For css-in-js we use jsx imported from @westpac/core and never depend on emotion directly other than inside core itself
👉 The file structure of components
├── README.md
├── package.json            # scope: `@westpac/`
├── src/                    # all the source
│   ├── overrides/          # all overrides files for each sub-component
│   ├── _util.js            # for reused logic within the component [optional]
│   ├── index.js            # only for exports
│   └── ComponentX.js       # only for the components, can be multiple files
├── examples/               # the demo folder is for seeing the components in action
│   ├── _util.js            # for reused logic within the examples [optional]
│   ├── 00-example.js       # show-case props and variations
│   ├── 10-example.js       # all files not starting with a dot or an underscore
│   └── 20-example.js       # will be processes with `yarn start`
├── demos/                  # the examples that can be embedded into the website
│   ├── example-x.js
│   ├── example-y.js
│   └── example-z.js
└── tests/                  # test includes all tests
    ├── integration/
    │   └── test.cypress.js # cypress test file for integration tests
    └── unit/
        └── unit.spec.js    # jest test file for unit tests
👉 npm scripts
yarn startstart the example server
yarn testruns test headless
yarn test:devruns test by opening cypress app
yarn test:integrationruns integration tests

Theming / Multi-brand

Multi-brand will be achieved by added a brand package that will be passed to the <GEL/> component

import { GEL } from '@westpac/core';
import brand from '@westpac/WBC';

export const App = () => <GEL brand={brand}>Your app</GEL>;

The brand package includes tokens and overrides and will be available to all packages inside the <GEL/> wrapper via context. This allows us to be as consistent as can be within the same app. It also separates out all things to do with theming into a single package. The brand package does not need to know anything about its components. But it can opt in.

👉 Tokens
COLORSOur colors including tints
LAYOUTOnly breakpoints so far
PACKSMostly typography packs for reuse and consistency
SPACINGA function with minor scale to allow you to hit the grid
TYPEFont files and definitions
BRANDThe current brand string


A consumer may choose to override a component in its build. This can happen by adding the overrides into the same namespace as the component you wish to override.

import { Tabcordion } from '@westpac/tabcordion';
import { GEL } from '@westpac/core';
import brand from '@westpac/wbc';

brand['@westpac/tabcordion'].TabItem.styles = ( styles, state ) => { ...styles, border: 'red solid 2px' };
brand['@westpac/tabcordion'].TabRow.component = <TabRow />;

export const App = () => (
    <GEL brand={brand}>
        All instances of the <Tabcordion/> now include the override specified above.
        No matter how many there are.

There may also a need to add an override only to a single instance of the component. In that case you may add the override to the component directly via the overrides prop each component has.

import { Tabcordion } from '@westpac/tabcordion';
import { GEL } from '@westpac/core';
import brand from '@westpac/wbc';

brand['@westpac/tabcordion'].Tabcordion.styles = ( styles, state ) => { ...styles, border: 'red solid 2px' };

const overrides = {
    Tabcordion: {
        styles: ( styles, state ) => { ...styles, border: 'blue solid 2px' },

export const App = () => (
    <GEL brand={brand}>
        <Tabcordion/> with red border
        <Tabcordion overrides={overrides} /> with blue border
        <Tabcordion/> with red border

(💡 Overrides will be reconciled as a cascade from less-specific to most-specific.)

Every single component (including root component) have three items in their override object:

overrides = {
    [name]: {
        styles: (base-styles, state-props) => styles,
        component: <React.Component/>
        attributes: (base-attributes, state-props) => Object,
👉 Overrides
KeyTypeDescriptionFunction arguments
stylesfunction => ObjectA function that returns an object of css properties for emotion(base-styles,state/props) base-styles = the styles that would have been applied to the component, state/props = all props and all known state (without setters)
attributesfunction => ObjectA function that returns an object of attributes that will be spread onto the component(base-attributes,state/props) base-attributes = the attributes that would have been applied to the component, state/props = all props and all known state (without setters)
componentreact componentA react component which will receive all props-

Data driven API

Components that are made up by other components like list, breadcrumb, button-group, input-group etc can be solely driven by the data prop. We also offer declarative APIs in-case a consumer wants to wrap a component.

    <Crumb href="#/" text="Home" />
    <Crumb href="#/personal-banking/" text="Personal" />
    <Crumb href="#/credit-cards/" text="Credit cards" />

Is the same as:

        { href: '#/', text: 'Home' },
        { href: '#/personal-banking/', text: 'Personal' },
        { href: '#/credit-cards/', text: 'Credit cards' },

How we handle focus state

We use the useFocus hook in the GEL component. You can read about the focus hook on medium. The GEL also adds the global focus styling from our PACKS.focus token pack. If you need to add it to something use:

':focus': {

However if you need a focus state that will persist across mouse users do something like this:

const { PACKS } = useBrand();

const focus = { ...PACKS.focus };
focus.outline += ' !important'; // adding `!important` will make sure the focus persists

        ':focus': { ...focus },
👉 Naming convention for files inside components
index.jsExport only public API
_utils.jsFor code shared between components (ignored in examples) [optional]
ComponentX.jsAll component files are named after the exported component and pascal cased
00-*.jsAll files inside the examples/ folder are sorted by file name
*.jsAll jsx files are postfixed with .js
*.spec.jsAll (jest) unit tests are postfixed with .spec.js
👉 Props API vocabulary
tagWhen a component can be rendered as different tags
lookWhen talking about the look of a component like success or hero
hrefWhen something points at a thing via a link
icon iconLeft iconRightFor passing in an icon
disabled or noBorderFor passing boolean flags we use natural language and not is or has prefixes
sizeFor the physical size of a component, should be: 'small', 'medium', 'large', 'xlarge'
spacingFor the whitespace size of a component, should be: 'small', 'medium', 'large', 'xlarge'
valueFor when a component shows a value, often numbers but not only
selectedFor things inside lists that are being targeted. Like ButtonGroups or CheckGroup. Takes string or array
assistiveTextFor labeling things for assistive technology (generally renders using VisuallyHidden or aria-label depending on use case)
xsmall small medium large xlargeFor t-shirt sizing
dataA prop to drive a component-group from data alone

Component build

This build is running all the components examples/demos directly and nothing else. It's for development of a component and for testing it.

You run it via:

cd path/to/root/of/repo
yarn dev [component name]

Docs build

This build is for the developer documentation site that puts all the examples of all components together with a navigation. It's for the docs that are automatically published to:


You run it via:

cd path/to/root/of/repo
yarn docs

Blender support

The blender can generate human readable html and css from react and emotion components.

Read more about how you add blender support in the blender README.md.

Rate & Review

Great Documentation0
Easy to Use0
Highly Customizable0
Bleeding Edge0
Responsive Maintainers0
Poor Documentation0
Hard to Use0
Unwelcoming Community0
No reviews found
Be the first to rate


No alternatives found


No tutorials found
Add a tutorial