Composing code
How to compose code effectively with using the Atlassian Design System.
Understand when to compose code
Compose code when you need to build something custom that isn't supported by Atlassian Design System (ADS) components. Use composition in software development to reuse code and customize easily. It saves time and reduces effort. Take the following steps to decide when to compose.
1. Use ADS components where possible
These pre-built solutions will be the easiest to create and maintain.
Components
Combine reusable building blocks to meet specific interaction needs and create consistent user experiences.2. Use available customization options if an ADS component isn’t enough
For example, we offer <Button appearance="primary" spacing="compact">
to customize a button. Or in
other places <Box xcss={{ padding: 'space.100' }}>
for bounded styles.
3. Use primitives and ADS components to add spacing and styles
To add spacing and styles where you need to, compose with primitives and ADS components using consistent APIs.
4. Use tokens and other foundations for purely custom components
Follow the guidance for our tokens and other foundations. Also Compose alongside our primitives and ADS components to have a UI that is consistent and easy to maintain.

Composing components and JSX
Developers and designers use composition patterns regularly. Our design system patterns make it easier to implement and control of components.
<Box padding="space.200">
<p>You have unread messages</p>
<Button appearance="primary">
Read messages <Badge appearance="primaryInverted">{5}</Badge>
</Button>
</Box>
We are focusing on promoting reusable components instead of large, complex ones with complicated interfaces. More inflexible APIs like our Dynamic Table may be changed and/or broken up into smaller components in the future to give you flexibility and control.

Composing styles and CSS-in-JS
When composing styles, separate styling concerns into individual components rather than styling in one large block. This way, changes are manageable as there's a clear (type-safe) connect to the component itself, rather than a loose connection through global or nested styles.
An example of what to do
We recommend using patterns like the example below. In the example, you have all the context to understand this component locally, understand the styles, and determine what happens when your props.selected changes. These patterns apply to both ADS primitives and native HTML elements (using Compiled or similar to style).
const wrapperStyles = xcss({
background: 'color.background.accent.blue.bolder',
});
const textStyles = css({
color: token('color.text.inverse'),
});
const selectedTextStyles = css({
textDecoration: 'underline',
});
export const Component = (props) => (
<Box padding="space.100" xcss={wrapperStyles}>
<span css={[textStyles, props.selected && selectedTextStyles]}>
Hello world
</span>
</Box>
);
Examples of what to avoid
We don't recommend the patterns in the below examples, as they become impossible to maintain at
scale. You have to interpret the DOM to understand the node tree and styles. If the <span>
element
is changed to a <p>
, the component breaks.
When implemented across multiple files, this becomes an anti-pattern that is very inefficient, error-prone, and causes regressions to our customers.
// shared/styles.ts
export default styled.div<any>`
padding: 8px;
background: #0C66E4;
> span {
color: #fff;
${props => props.selected && 'text-decoration: underline !important'}
}
// component.ts
import Wrapper from '../shared/styles.ts';
export const Component = (props) => (
<Wrapper selected={props.selected}>
<span>Hello world</span>
</Wrapper>
);
A practical example of composition in action
Our primitive documentation and examples show composition in action.
Precautions when you’re composing code
- Use pre-built components for a consistent, accessible, and easier-to-maintain user experience.
- Keep design and styling decisions in one file to maintain clear, local context.
- Organize files by context, not by code type, for better clarity and maintainability.
- Prevent unintended code impacts by keeping related decisions together.
- Be aware of of parent/child component changes affecting layouts over time. For example, if the ADS Modal component for example changes its padding, your composed inner layout may look a bit out-of-place.
- Use visual regression testing and image snapshots to ensure design consistency when working with external design decisions.