Sainsbury’s Luna Design System Codebase

Edward Mortlock
Sainsbury’s Tech Engineering
7 min readDec 17, 2019
Luna Design System by Sainsbury’s hero logo

What is Luna?

Luna is a design system created by Sainsbury’s for products across the group which aims to promote UI consistency, ease of development and the best possible experiences for end-users.

For more information about design systems in general DesignBetter.co have created the fantastic Design Systems Handbook, which covers every aspect on the topic.

Luna itself can be split into 3 main facets:

  • Documentation — Not everyone’s favourite job, but understanding how to use the tools a system offers and to expand on the principles it’s built on is absolutely key for long term success of a design system. We use our website, http://luna.sainsburys.co.uk/, to detail what’s available, how / when to use them and what standards are applied in terms of aspects like accessibility.
  • Design —Leveraging Sketch Libraries we make our prebuilt components available for designers to use within Sketch.
  • Code — Where we’ll be focussing in this article. We have a number of libraries available for projects offering React components and Sass styling as well as some helper tools to speed up front-end development.

Luna Codebase

MacBook showing VSCode screenshot of the Luna Codebase

The core set of tools used to build sites using Luna are part of a monorepo managed by Lerna. This allows us to produce multiple independent packages from within one workspace whilst still allowing for improved code sharing and orchestration of releases.

We have separated out components into smaller package groups to allow for better control over what is imported into a project. This reduces the reliance on tree shaking (which can be… inconsistent at times) for bundle size optimisation as well as offering more flexibility in how upgrades are managed. However, we still offer compilation packages which allow for easy access to all that Luna has to offer depending on the project set up:

  • Luna Style — An agnostic styling layer that allows for Sass or CSS implementation. Through Sass variables theming can be changed as well as switching features off to reduce output.
  • Luna React — A component library allowing for easy implementation of the Luna Style classes through premade stateful and presentational components that offer a high degree of customisation through props and composition.

To ease the pathway for contributions from product teams we also have the Luna Labs project for in-progress components that, whilst they will generally be production-ready, may not have had the full suite of accessibility and usability testing we perform for core patterns.

Luna Style

This library provides either Sass or CSS distributions of the Luna styling which you can apply to your code via standard CSS class naming on elements.

<button  class=”ln-c-button ln-c-button — filled” type=“button”>
 Click me!
</button>

Luna Style uses a combination of ITCSS & BEM methodologies for scalable CSS architecture, which is reflected in the class names you see above. It is also built using mobile-first principles development, where you approach requirements with the smallest screen in mind.

Structure

The ITCSS triangle with grouped by the Luna packages that cover that layer

ITCSS has influenced how we have structured our styling packages, we’ve split the triangle into purpose-built libraries. This gives more semantic meaning in terms of their import order and flexibility for opting into the relevant levels you need.

For example, using the object layout helpers it is perfectly possible to include Luna without actually making use of any of the cosmetic elements (not that we’d recommend that!). This follows our baseline grid and those spacing variables in the foundation layer are used across the entire system creating a consistent vertical rhythm throughout the page.

Class naming

Taking .ln-c-button--filled and .ln-c-button__icon as examples we can break those apart into the following:

  • ln — All Luna classes have a namespace prefix to avoid any conflict with styles in your project.
  • c — This links the class to its related ITCSS section, with c denoting it as a component with cosmetic styling, o is used for layout tools and u signifies a class as a utility with the highest specificity but smallest reach, typically only changing one property.
  • button — The block aspect of BEM where this would be the name of the component or layout structure being applied.
  • __icon or --filled — The final parts of the class cover the element and modifier of BEM. Element, represented by underscores, signifies the class is a child within its related block whereas modifier, using hyphens, is used for variations of the block.

Luna React

The granular component packages that make up the Luna component library styled as a periodic table

For React applications you can use Luna React in conjunction with Luna Style in order to easily make use of the available components.

import { FilledButton } from ‘@jsluna/react’
 
 <FilledButton>
 Click me!
 </FilledButton>

Through the use of Luna Style, it’s possible to make use of all the patterns promoted by Luna, but Luna React takes away a lot of the effort and thought needed in order to achieve that. Taking an example of a set of accordions, we have the HTML implementation:

Large code block detailing the SVGs, semantic tags and aria attributes required to make an accessible accordion

Which not only requires a non-trivial amount of HTML to be typed out (think of your poor fingers!), but it also needs awareness of the relevant accessibility approaches used to give the best experience to users who need assistive devices. This can be the aria attributes and unique id's needed to link elements together or use of semantic role attributes and HTML tag names.

When using Luna React all of that is built-in, so you’re able to concentrate on the content.

import { Accordion } from ‘@jsluna/accordion’
 
 <Accordion title=”Title”>
 Body
 </Accordion>

With the React components, we have always aimed to be agnostic of other libraries so don’t step on the toes of tools like Formik and React Router which are obviously widely popular across our teams. Where applicable we have extensions to core components that make use of Recompose HOC functionality in order to adapt to the format the third party library expects.

More than code?

Unfortunately the ‘build it and they will come’ philosophy doesn’t always apply with internal tools, along with quality code there’s always those extra value-added features that make the difference and start building a bit of momentum. This could be an article in itself so I’ll just highlight a few here.

Support & outreach

As is the case with using any new library there are always going to be issues in understanding concepts or wanting to use it in an undocumented way so this is an absolutely key one to ensure a system actually gets used.

With Luna, we perform onboarding sessions with teams new to the system where we go through the above content and run through a live coding demo. We follow that up with active support through dedicated channels on MS Teams and sitting with teams when visiting the different sites.

Even with a dedicated team around the design system you’ll never be able to keep up with the evolving needs and support requirements of consuming projects. Fostering a community around the system is massively important to get buy in for encouraging initial adoption as well as the benefits that brings from people sharing their suggestions, helping each other and contributing new patterns back in. For Luna we have always pushed for it to be considered open source within the company and are as responsive as possible to PRs and issues raised on GitHub.

Accessibility

All our components have been developed with access needs in mind, with research performed to give the best possible experience for those users. We’ve had the benefit of having an awesome specialist in this area to help us validate approaches by testing in popular screen reader solutions and by running sessions with users with access needs.

We also have extensive documentation on the accessibility standards we follow, with plenty of practical advice available. In addition, as part of usage documentation for components, we detail any custom aria that may be required depending on use.

Whilst we are really pleased with the progress we’ve made in this area (and will continue to do so, as there is always improvements that can be made), it’s important to note that making use of Luna or other systems doesn’t automatically make your site accessible. There is always going to be content that is specific to your project and so should follow accessibility best practice. Another factor to consider is that most accessibility solutions are very dependent on the context the component is being used in, so care should be paid to props that can give more relevant experiences to users making use of screen reader software.

More to come…

It has been a great journey to get to where we are at with Luna, with over 2 years of work from the dedicated Luna team, and lots of lessons learned so hopefully we’ll be able to post more about the design system and how those lessons can be applied to starting up your own system soon.

I would also like to thank my Luna team colleagues Mike Beach, David Chan, and Anthony Tran for helping with the article.

--

--