Building

Component Structure

The pattern should be exported as a named export from a file matching the pattern name in the pattern folder.

Any pattern specific styled components used in the jsx for the patterns react component should come from an adjacent <Pattern>.styled.ts file.

Sub components (react components which are not part of the patterns public api, but used as part of the main react component) should be setup under a components folder.

Patterns should be exported from their module using a "barrel file" - an index.ts file which re-exports the public elements of the pattern.

- ./Tabs
- /components
- /Tab
- Tab.tsx
- CHANGELOG.md
- README.md
- index.ts
- Tabs.tsx
- Tabs.styled.ts
- Tabs.test.tsx
- Tabs.vr-test.tsx
// ./Tabs/components/Tab/Tab.tsx
import * as React from 'react';
import styled from 'styled-components';
export const StyledTabContainer = styled.div`
/* styles */
`;
export const Tab: React.FunctionComponent = (props) => {
return <StyledTabContainer>{props.children}</StyledTabContainer>;
};
// ./Tabs/Tabs.styled.ts
import * as React from 'react';
import styled from 'styled-components';
export const StyledTabsContainer = styled.div`
/* styles */
`;
// ./Tabs/Tabs.tsx
import * as React from 'react';
import { Tab } from './components/Tab.tsx';
import { StyledTabsContainer } from './styled.tsx';
interface Props {
tabTitles: string[];
}
export const Tabs: React.FunctionComponent<Props> = (props) => {
return (
<StyledTabsContainer>
{props.tabTitles.map((tabTitle) => (
<Tab key={tabTitle}>{tabTitle}</Tab>
))}
</StyledTabsContainer>
);
};
// ./Tabs/index.ts (the barrel file)
export * from './Tabs';

How to structure props

The props interface should;

  • be directly above the react component it is for,
  • should not extend other types
  • if it contains nested types used by internal child components (ie declared in a file under /components)
    • these should be declared in the main component file, above the Props interface
  • and a consumer should be able to reason about it without having to open other files.
// ./Tabs/Tabs.tsx
interface TabProps {
/** title displayed on tab button */
title: string;
}
interface Props {
tabs: Tab[];
}
export const Tabs: React.FunctionComponent<Props> = (props) => {
return (
<StyledTabsContainer>
{props.tabs.map((tab) => (
<Tab key={tab.title} title={tab.title} />
))}
</StyledTabsContainer>
);
};
// ./Tabs/components/Tab/Tab.tsx
import { TabProps } from '../Tabs';
export const Tab: React.FunctionComponent<TabProps> = (props) => {
return <StyledTabContainer>{props.title}</StyledTabContainer>;
};

Styled Components Naming Convention

All styled-components should be prefixed with "Styled".

export const StyledTabsContainer = styled.div``;
export const StyledTabTitle = styled.span``;

Styles Guidance

Formatting and Structure

  • Add a line break between declarations
  • Grouping
    • Interactive States (e.g. hover) should be grouped and come after base theme styles
    • Breakpoints should be included after states and grouped under the breakpoint name (these should increase based on size, e.g. sm, md, lg)

Ordering

The following outlines the order for writing your styled components styles in a way that will be easier for you to manage.

  1. External Styles
    • Knowing that you are inheriting a bunch of styles from somewhere else is important, and listing first means you can override the inherited set if you need to.
  2. Component Styles (includes interactive states and breakpoints)
    • Adding component styles after allows us to properly override those properties if needed (Overriding styles should be limited as much as possible)
  3. Media Queries
    • Media queries typically affect regular styles or includes so we nest them before any pseudo elements of selectors
  4. Pseudo-classes and pseudo-elements
    • Pseudo elements and pseudo classes are directly related to the element itself so, for that reason, we nest them first before other selectors.
  5. Variant Styles
    • Variant styles which are how are variants unique visual execution are achieved
  6. State Styles
    • States styles should be common across variants and should work for all variants
  7. Nested components
    • Nested selectors should be avoided where possible, if needed they should come after pseudo-classes and pseudo-elements

Additional usage guidelines

Colours

  • Should reference a pre-defined colour from ./src/styles/theme.colours.ts
  • If it doesn't exist in ./src/styles/theme.colours.ts speak with design about either
    • adjusting to use one of these colours
    • or adding a new colour

Z-indexing Management

All z-indexes must be defined in the global z-index file under ./src/styles/zIndex.ts

Absolutely no hardcoded z-indexes allowed in the codebase.

JavaScript Hooks

If needed for third parties, javascript hooks can be added as classes, they should be prefixed e.g. gtm-track, gemini-card etc

This is to ensure we don't remove classes that are used by other scripts

Styled Components class names

DO NOT rely on styled components class names in your css or js - as they are based on a hash of the styles and will change with style changes.

CSS Entities for Pseudo-elements

When declaring css entities in a style object you need write css entities slightly different

content: '\\002f', // instead of content: '/002f',

To help, here is a handy conversion table: https://brajeshwar.github.io/entities/

CSS Property Order and Grouping

[[TODO: SUPPORT WITH LINTING]] While this would be great we do not expect you to do this without linting so don't get hung up on it, no one's going to pull you up on it!

Grouping your properties will help to create consistent stylesheets.

Grouping order:

  • Positioning - Positioning comes first because it can remove an element from the normal flow of the document and override box model related styles.
  • Layout - Dictates a components dimensions and placement.
  • Typography
  • Visual

Typography and visual come last because they take place inside the component or without having an impact on positioning and box model.

/** positioning */
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 1;
/** layout */
display: block;
float: right;
width: 10rem;
height: 10rem;
padding: 1rem;
margin: 1rem;
/** text */
font-size: 1rem;
line-height: 1.5;
color: #fff;
text-align: center;
/** visual */
background-color: #fff;
border: 1px solid #000000;
border-radius: 3px;
/** misc */
opacity: 1;