Composing code

How to compose code effectively with using the Atlassian Design System.
Banner for Composing code page

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

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.

Compose with primitives

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.

Contact us

Slack a question (Atlassians only)

Reach out to our team in our Slack channel.
, (opens new window)
Was this page helpful?
We use this feedback to improve our documentation.

What's new

Featured2025
© 2025 Atlassian