Proposing changes
Octopus product designers are encouraged to propose changes to our design system accordingly to our contribution model. Depending on the contribution size, create a branch in Figma (Fix and Light contributions) or use the Component Proposal file to introduce your changes (Medium and Large contributions).
Creating the component
Naming
Name of the component should be identical in design and code. Component names use PascalCase and should follow our naming conventions.
Documentation
We primarily document components in our design system documentation. We also have a Component Showcase for creating playground and examples of each component.
Folder organisation
There are two places you will need to create files when creating a new component.
- In the Design System Components package (/design-system-components)
- In the Component Showcase package (/component-showcase)
Adding to the Design System Component Package
When creating the component you will create a folder for each component with the name of the component under design-system-components/src/components e.g. src/components/ComponentName
This folder should include:
- The component ( ComponentName.tsx )
- Functional Tests under a __testing__ folder with files suffixed with .spec.tsx e.g. ComponentName.spec.tsx
- Any related sub components
- An index.tsx for exporting
You should keep one folder per component unless they are sub components.
Adding to the Component Showcase Package
We use Storybook for creating examples for the Component showcase to do this you will create a folder with the name of the component under the component categorisation from Figma, e.g. Navigation, Overlay, Form Elements. The storybook story will be named with the component name and suffixed with .stories.tsx e.g. ComponentName.stories.tsx
The navigation for the component showcase is generated based on the title provided in the story.
For Example
const meta = {
title: "Components/Navigation/Pagination",
component: Pagination,
tags: ["autodocs", "stable"],
} satisfies Meta<typeof Pagination>;
This will put the Pagination under Components>Navigation>Pagination in the navigation. Changing this will change the Storybook URL and therefore require you to update any links in Documentation.
Adding Tags to Component Showcase
When creating a Story you will always want to include autodocs in the tags. Other options will depend on the status of the component. Refer to the Component Status documentation for more information.
Supported Status Tags
- stable
- deprecated
- in-progress
- code-only
- needs-review
Properties
All properties and values are written in camelCase. We do our best to align the property names with Figma.
Common examples
|
Property name |
Example values |
Usage |
|---|---|---|
|
type |
primary, secondary, tertiary |
Defines a hierarchy of component variant usage. Useful in common scenarios such as Button component. |
|
disabled |
true, false |
Defines if an element is disabled in terms of turning off interactivity or functionality. |
|
readOnly |
true, false |
Defines if the element is read only. |
|
isMuted |
true, false |
Defines if an element has a visually less prominent appearance that might hint it’s disabled, but no functionality or interactivity is turned off. |
|
size |
xSmall, small, medium, large, xLarge, xxLarge |
Defines standardized sizes for components. Use t-shirt sizing with a value in parenthesis as the same names might mean different widths for different components (e.g.: xs (14px)). |
|
width |
xSmall, small, medium, large, xLarge, xxLarge, fullWidth |
Defines standardized width for components. Use t-shirt sizing with a value in parenthesis as the same names might mean different widths for different components (e.g.: xs (14px)). |
|
shape |
square, circle |
Defines the shape of the component. |
|
{item}Position |
top, bottom, left, right |
Defines the position of an element. E.g. an arrow in a Tooltip component. |
|
{item}Count |
1, 2, 3, 4, 5, 6, 7 |
Defines the number of nested component instances. E.g. a number of Radio options in a Radio Group. |
Note that the table above doesn’t cover all possible cases that you might need to create. When in doubt, ask yourself:
- Can the name and the options be easily understood without additional context and documentation?
- Does it accurately represent what the property does?
The clearer and more succinct the naming, the better.
States in components
Interactive components should visually communicate their different interaction states such as rest, hover, focus, and active.
These states map to corresponding CSS pseudo-classes. You should always include these states in your component implementation. If they are not defined in the design files, please reach out to your designer or contact #team-frontend-foundations-requests for guidance.
Focus states
We generally use the :focus-visible pseudo-class to define focus styles. This ensures that focus indicators appear only when navigating with the keyboard, improving accessibility and reducing visual noise for mouse users.
However, there are exceptions, particularly in form components, where a visible focus state helps users understand which input field is currently active.
If you determine that your component benefits from a focus state that is always visible, we encourage you to instead use the standard :focus selector.
Properties: Boolean
When naming a boolean property, consider the following naming conventions.
|
Boolean property name |
Example values |
Usage |
|---|---|---|
|
is-{verb} |
isLoading |
Useful when portraying that a parent component is in a certain state that cannot be expressed using property variants, especially when controlling visibility of multiple items. |
|
has-{item} |
hasIcon |
Useful when portraying that a parent component has a specific, singular item. |
|
show-{item} |
showExpandCollapseIcon |
Useful when specificity in the element we’re controlling is necessary for clarity. |
Multiple components vs multiple variants
In some cases, it’s not evident if similar components should be handled as separate or variants of the same component because of similarities. When deciding between these two approaches, consider:
-
Does the change strictly visual or significantly alter the functionality of the component? When new functionality is added, it can warrant creating a separate component (that might or might not inherit from another component through nested instances)
Example: Avatar vs AvatarStack. The latter uses Avatar with added functionality that is irrelevant to all use cases
-
Does the chosen approach negatively influence maintenance? If the components are separated but very similar in terms of appearance and function, it increases the maintenance cost on the design and code sides
Example: PopoverComplex and PopoverHelp. Both are similar enough to be variants of the same component, reducing the maintenance overhead.
Maintenance & Deprecation
If you are deprecating a component please refer to our Deprecation Guidelines for further information.