Migration guide

Neutral selected states

When the platform-dst-tokens-finesse feature flag is enabled, this component uses the new neutral treatment for selected states.

Motion in Early Access

Motion updates for multi-value Select tags are in Early Access and available behind the platform-dst-motion-uplift-labels feature flag.

Note: Select is migrated to Compiled in v22.0. Follow this migration guide to migrate Select in pre-22.0 versions.

Overview

Atlaskit Select has been migrated from Emotion to Compiled CSS-in-JS to improve performance and enable React 18 Streaming SSR compatibility. This guide will help you migrate your existing Select customizations to the new approach.

Migration approach

The migration introduces an enhanced components API that replaces the styles prop with the xcss prop for better performance and type safety.

Before and after comparison

Old approach (Emotion with styles prop)

import Select from '@atlaskit/select';
import { token } from '@atlaskit/tokens';

const customStyles = {
    control: (base, state) => ({
        ...base,
        backgroundColor: token('elevation.surface'),
    }),
};

const MyComponent = () => <Select options={options} styles={customStyles} />;

New approach (Compiled with components API)

/** @jsx jsx */
import { cssMap, cx } from '@atlaskit/css';
import Select, { components } from '@atlaskit/select';
import { token } from '@atlaskit/tokens';

const controlStyles = cssMap({
    root: {
        backgroundColor: token('elevation.surface'),
    },
});

const MyComponent = () => (
    <Select
        options={options}
        components={{
            Control: (props) => <components.Control {...props} xcss={controlStyles.root} />,
        }}
    />
);

Component mapping reference

When migrating from styles prop to components API, use this mapping:

styles prop keycomponents API key
clearIndicatorClearIndicator
containerSelectContainer
controlControl
dropdownIndicatorDropdownIndicator
groupGroup
groupHeadingGroupHeading
indicatorsContainerIndicatorsContainer
inputInput
loadingIndicatorLoadingIndicator
loadingMessageLoadingMessage
menuMenu
menuListMenuList
menuPortalMenuPortal
multiValueMultiValueContainer
multiValueLabelMultiValueLabel
multiValueRemoveMultiValueRemove
noOptionsMessageNoOptionsMessage
optionOption
placeholderPlaceholder
singleValueSingleValue
valueContainerValueContainer

Step-by-step migration process

1. Update imports

// Add these imports
/** @jsx jsx */
import { cssMap, cx } from '@atlaskit/css';
import Select, { components } from '@atlaskit/select';

2. Convert styles to cssMap

// Old styles object
const customStyles = {
    control: (base, state) => ({
        ...base,
        minHeight: '40px',
        borderRadius: token('radius.large'),
    }),
};

// New cssMap approach
const controlStyles = cssMap({
    root: {
        minHeight: '40px',
        borderRadius: token('radius.large'),
    },
});

3. Replace styles prop with components API

// Old approach
<Select styles={customStyles} />

// New approach
<Select
  components={{
    Control: (props) => (
      <components.Control {...props} xcss={controlStyles.root} />
    ),
  }}
/>

Advanced migration patterns

State-based styling

const controlStyles = cssMap({
    root: {
        minHeight: '32px',
        borderRadius: token('radius.small'),
    },
    focused: {
        borderColor: token('color.border.focused'),
    },
    disabled: {
        cursor: 'not-allowed',
    },
});

// Usage with conditional styling
<components.Control
    {...props}
    xcss={cx(
        controlStyles.root,
        props.isFocused && controlStyles.focused,
        props.isDisabled && controlStyles.disabled,
    )}
/>;

Multi-value styling

const multiValueStyles = cssMap({
    container: {
        backgroundColor: token('color.background.warning'),
    },
    label: {
        color: token('color.text.warning'),
        fontWeight: 'bold',
    },
    remove: {
        color: token('color.text.warning'),

        '&:hover': {
            backgroundColor: token('color.background.warning.subtle'),
        },
    },
});

// Usage
<Select
    components={{
        MultiValueContainer: (props) => (
            <components.MultiValueContainer {...props} xcss={multiValueStyles.container} />
        ),
        MultiValueLabel: (props) => (
            <components.MultiValueLabel {...props} xcss={multiValueStyles.label} />
        ),
        MultiValueRemove: (props) => (
            <components.MultiValueRemove {...props} xcss={multiValueStyles.remove} />
        ),
    }}
/>;

Backward compatibility

What still works

Most existing styles prop definitions will continue to work, but with limitations:

// This will still work (basic inline styles)
<Select
    styles={{
        control: (base) => ({
            ...base,
            backgroundColor: token('elevation.surface'),
            minHeight: '40px',
        }),
    }}
/>

What no longer works

The following CSS selectors are not supported in the styles prop:

  • Pseudo-classes/elements: :hover, :focus, :active, :disabled, :before, :after
  • Attribute selectors: [type="text"], [disabled]
  • Combinators: > (child), + (adjacent sibling), ~ (general sibling)
  • Universal selector: *
  • ID selector: #myId
  • Class selector: .myClass
  • At-rules: @media, @supports
  • Parent selector: &
  • Namespace separator: |
  • Attribute operators: ^=, $=, =

If your styles use any of these selectors, you must migrate to the components API.

Performance best practices

  • Use Design Tokens: Always use @atlaskit/tokens for consistent theming.
  • Minimize Style Objects: Keep cssMap objects focused and reusable.
  • Avoid using styles props: Migrate away from styles prop completely.
  • Leverage State Props: Use component props for conditional styling instead of complex selectors.
Was this page helpful?
We use this feedback to improve our documentation.
  • Design system
    • Get started
    • Foundations
    • Components
    • Rovo UI
    • Tools
    • Release phases
    • Contact us
© 2026 AtlassianTrademark, (opens new window)Privacy, (opens new window)License