@atlaskit/primitives
Version:
Primitives are token-backed low-level building blocks.
137 lines (106 loc) • 3.53 kB
text/mdx
---
title: Migrating your app to XCSS
description: XCSS is a safer, tokens-first approach to CSS-in-JS.
order: 2
---
## Summary of changes
### Changes for developers
There are two key changes to be mindful of when migrating to XCSS. The first is updating callsites
to remove any nested styles and tokenized values.
```diff
- import { css } from '@emotion/react';
+ import { xcss } from '@atlaskit/primitives';
- const someStyles = css({
+ const someStyles = xcss({
// token based properties will no longer need to be wrapped
- padding: token('space.100'),
+ padding: 'space.100'
// no change is required for non-tokenized values
transform: 'scale(2)'
});
```
The second change is that for the `xcss` function to be applied correctly it must be applied on a
component with an `xcss` JSXAttribute. This won't work with the `css` or `className` JSXAttributes,
be aware if you're not seeing your styles appear.
```diff
- <div css={someStyles} />
+ <Box xcss={someStyles} />
```
### Changing the way you express styles
Why are nested selectors a problem? A key philosophy of XCSS is encouraging more deterministic style
application. Restricting nested styles eliminates side-effects and encourages component
encapsulation. Consider the below example:
```tsx
const myComponentStyles = css({
'> *': {
color: 'color.text.danger',
},
});
const MyComponent = () => (
<div css={myComponentStyles}>
<p>Text here</p>
</div>
);
```
Here the component is applying styles that are implicitly meant for the text wrapped in the `p`
below. In this simple example, it may seem okay, desirable even, but cases like these often occur
across module or component boundaries.
This makes the visibility of these dependencies harder to capture or reason about. Styles that are
inherited or indirectly apply make a UI vulnerable to change and harder to maintain. Instead, if the
same styles are applied directly to the affected element this can minimize and in some cases
completely eliminate this problem.
```diff
const myTextStyles = xcss({
- '> *': {
color: 'color.text.danger',
- }
});
const MyComponent = () => (
- <div xcss={myComponentStyles}>
+ <Box
+ <Text xcss={myTextStyles}>Text here</Text>
</Box>
);
```
There will likely be cases where nesting is the only option. While not desirable, nesting can be
used minimally, and when the potential impact is considered.
## FAQ
Migration to XCSS is simple for the majority of cases. Here are some common strategies for
migrations.
### Non-tokenized values
Before migrating to tokens, there are two options. Migrate to tokens first and then on a second pass
migrate to XCSS or make the jump directly to use both tokens and XCSS.
```tsx
const someStyles = css({
color: 'red',
});
// ->>> Optional middle step
const someStyles = css({
color: token('color.text.danger'),
});
// ->>> The final state
const someStyles = xcss({
color: 'color.text.danger',
});
```
### Moving from the `styled` API
If currently using the `styled` API there are a few steps to migrate. The safest approach is to use
object styles, migrate to tokens (optionally) and then migrate to XCSS.
```tsx
const MyComponent = styled.div`
color: red;
`;
// ->>> move to object styles
const MyComponent = styled.div({
color: 'red';
});
// ->>> move to tokens
const MyComponent = styled.div({
color: token('color.text.danger'),
});
// ->>> move to Box
const myComponentStyles = xcss({
color: 'color.text.danger',
});
const MyComponent = () => <Box xcss={myComponentStyles} />
```