Some of the changes in this guide can be automated using the ESLint and Stylelint plugins. Changes that can be automated are marked with a robot emoji (π€) and the name of the rule (e.g. no-deprecated-props)
We encourage you to enable and apply the rules incrementally and review the changes before continuing. The rules don't cover all edge cases, so further manual changes might be necessary. For example, the ESLint rules only analyze one file at a time, so if a Circuit UI component is wrapped in a styled component in one file and used in another, ESLint won't be able to update its props.
Prior to v5, codemods were implemented using jscodeshift.
Circuit UI v9 introduces a new typeface, more flexible typography APIs, and stable input components for colors, dates, and phone numbers. For a complete list of changes, refer to the changelog.
Circuit UI now requires at minimum Node.js v20. Note that Node 18 reached its end-of-life in October 2024.
We strongly recommend upgrading to Foundry v8.3+ which adds support for the Circuit UI ESLint plugin's new package scope and prevents dependency conflicts in the shared @typescript-eslint/*
dependencies. If you're unable to upgrade, manually add the Circuit UI ESLint plugin to your ESLint config and enable the relevant rules.
The packages have moved from the @sumup
to the @sumup-oss
scope to avoid conflicts with private packages. To get started, remove the old design system packages, then install the new ones:
npm uninstall @sumup/circuit-ui @sumup/design-tokens @sumup/icons @sumup/intl
npm install @sumup-oss/circuit-ui @sumup-oss/design-tokens @sumup-oss/icons @sumup-oss/intl temporal-polyfill
Note that temporal-polyfill
is a new required peer dependency and that the @sumup-oss/intl
peer dependency has been upgraded to v3. If your app also depends on @sumup-oss/intl
(previously called @sumup/intl
), you need to upgrade it as well. Refer to its changelog for migration instructions.
Follow the same process to upgrade any linter plugins your app is using:
# ESLint
npm uninstall @sumup/eslint-plugin-circuit-ui
npm install @sumup-oss/eslint-plugin-circuit-ui
# Stylelint
npm uninstall @sumup/stylelint-plugin-circuit-ui
npm install @sumup-oss/stylelint-plugin-circuit-ui
Update any static and dynamic imports to the new package scope (π€ renamed-package-scope
). The ESLint rule might not catch all occurrences of the old package names, so manually search for and fix any left-overs after applying the ESLint rule. For example:
-import { Button, type ButtonProps } from '@sumup/circuit-ui';
+import { Button, type ButtonProps } from '@sumup-oss/circuit-ui';
-jest.mock('@sumup-oss/circuit-ui', () => ({
- ...jest.requireActual<typeof import('@sumup-oss/circuit-ui')>(
- '@sumup-oss/circuit-ui',
- ),
-}));
+jest.mock('@sumup-oss/circuit-ui', () => ({
+ ...jest.requireActual<typeof import('@sumup-oss/circuit-ui')>(
+ '@sumup-oss/circuit-ui',
+ ),
+}));
The default typeface has changed from Aktiv Grotesk to Inter, a variable font. Variable fonts combine a continuous range of weights and other "axes" into a single file. This speeds up page load times and enables more creative freedom. Inter is a close match to Aktiv Grotesk, so the change should be seamless.
Circuit UI no longer loads the fonts by default. Instead, import the stylesheet that contains the font face declarations globally in your application, such as in a global layout file:
import '@sumup-oss/design-tokens/fonts.css';
To speed up the loading of the fonts, add preload links to the global <head>
element of your application. Choose which subsets to preload based on the languages your app supports. The available subsets are latin
, latin-ext
, cyrillic
, cyrillic-ext
, greek
, greek-ext
, and vietnamese
.
<link
rel="preload"
href="https://static.sumup.com/fonts/Inter/Inter-normal-latin.woff2"
as="font"
type="font/woff2"
crossorigin
/>
The typography components have been redesigned to improve visual hierarchy, ensure consistency across platforms and provide more flexible APIs for developers. The changes are fully backward compatible and can be adopted gradually.
The Title component has been renamed to Display for consistency with other platforms. The SubHeadline component has been deprecated in favor of the Headline component in size s
. The BodyLarge component has been deprecated in favor of the Body component in size l
(π€ no-deprecated-components
).
The Body component's variant
prop has been split into individual color
, weight
and decoration
props. Use the color
prop instead of the alert
, confirm
and subtle
variants, use the weight
prop instead of the highlight
variant, and use custom CSS to replicate the quote
variant (π€ no-renamed-props
). The new decoration
prop makes it easier to apply italic
and strikethrough
styles.
The sizes of the Display (formerly Title), Headline, and Body components have been consolidated and renamed to enforce greater visual hierarchy. Here's how the old size names map to the new ones (π€ no-renamed-props
):
Display
Old | New |
---|---|
one | l |
two | m |
three | m |
four | s |
Headline
Old | New |
---|---|
one | l |
two | m |
three | s |
four | s |
Body
Old | New |
---|---|
one | m |
two | s |
The typography design tokens have been updated accordingly (π€ no-deprecated-custom-properties
(ESLint & Stylelint)):
Old | New |
---|---|
typography-title-one-font-size |
display-l-font-size |
typography-title-one-line-height |
display-l-line-height |
typography-title-two-font-size |
display-m-font-size |
typography-title-two-line-height |
display-m-line-height |
typography-title-three-font-size |
display-m-font-size |
typography-title-three-line-height |
display-m-line-height |
typography-title-four-font-size |
display-s-font-size |
typography-title-four-line-height |
display-s-line-height |
typography-headline-one-font-size |
headline-l-font-size |
typography-headline-one-line-height |
headline-l-line-height |
typography-headline-two-font-size |
headline-m-font-size |
typography-headline-two-line-height |
headline-m-line-height |
typography-headline-three-font-size |
headline-m-font-size |
typography-headline-three-line-height |
headline-m-line-height |
typography-headline-four-font-size |
headline-s-font-size |
typography-headline-four-line-height |
headline-s-line-height |
typography-sub-headline-font-size |
headline-s-font-size |
typography-sub-headline-line-height |
headline-s-line-height |
typography-body-large-font-size |
body-l-font-size |
typography-body-large-line-height |
body-l-line-height |
typography-body-one-font-size |
body-m-font-size |
typography-body-one-line-height |
body-m-line-height |
typography-body-two-font-size |
body-s-font-size |
typography-body-two-line-height |
body-s-line-height |
The new Compact component should be used to label information in space-constraint contexts.
The new Numeral component should be used to give emphasis to numerical content such as currency values.
All experimental components are now stable.
- The Calendar and DateInput components have been rebuilt from scratch for better performance and accessibility. They replace the legacy RangePicker, RangePickerController, SingleDayPicker, CalendarTag, and CalendarTagTwoStep components, which have been removed. The DateInput component now requires additional localized label props.
- The ColorInput and PhoneNumberInput components enable users to enter hex colors and phone numbers respectively.
- The Tooltip and Toggletip components have been rebuilt from scratch for improved accessibility. They replace the legacy Tooltip component.
Update the related imports (π€ component-lifecycle-imports
). For example:
- import { Calendar, type CalendarProps, type PlainDateRange } from '@sumup-oss/circuit-ui/experimental';
+ import { Calendar, type CalendarProps, type PlainDateRange } from '@sumup-oss/circuit-ui';
-
Changed the
PlainDateRange
type from an array to an object with start and end properties. This affects the Calendar component'sselection
prop. Use the newupdatePlainDateRange
helper function to update a date range when a user selects a date:import { useState } from 'react'; import { Calendar, updatePlainDateRange } from '@sumup-oss/circuit-ui'; function Component() { const [selection, setSelection] = useState({}); return ( <Calendar onSelect={setSelection((prevSelection) => updatePlainDateRange(prevSelection, date) )} /> ); }
-
Deprecated the
InputElement
interface and narrowed the Input component's element type toHTMLInputElement
and the TextArea component's element type toHTMLTextAreaElement
. This affectsref
s and event handlers.-import { InputElement } from '@sumup-oss/circuit-ui'; -ChangeHandler<InputElement> +ChangeHandler<HTMLInputElement> -useRef<InputElement>() +useRef<HTMLInputElement>()
-
Removed the Table component's deprecated
initialSortedRow
prop. Use theinitialSortedColumn
prop instead (π€no-renamed-props
).
Circuit UI v8 introduces a redesigned Button component and switches the brand color from blue to black.
To get started, upgrade @sumup/circuit-ui
and its peer dependencies:
npm upgrade @sumup/circuit-ui @sumup/design-tokens @sumup/icons
Upgrade any linter plugins your app is using:
# ESLint
npm upgrade @sumup/eslint-plugin-circuit-ui
# Stylelint
npm upgrade @sumup/stylelint-plugin-circuit-ui
The Button component has been redesigned from the ground up. Corners are now rounded instead of pill-shaped, the tertiary variant now sports an underline to improve accessibility, and the loading spinner has been replaced with three animated dots. Long button labels that would previously wrap are now truncated to a single line with a trailing ellipsis.
The ButtonGroup component now uses a container query (instead of a media query) to switch to a horizontal layout. This makes it possible to use it in narrow spaces such as the SidePanel component.
Check whether any custom styles applied to a Button clash with the new design. Here are some common patterns we've observed and how to migrate them:
- Tertiary Button with (horizontal) padding removed: A tertiary button should only be used next to a primary or secondary one and never alone. Use an Anchor with
variant="highlight"
or a secondary Button instead.
To improve accessibility, the Button's disabled
attribute has been replaced with the aria-disabled
attribute which enables the disabled element to receive focus and be perceived by screenreader users. Interactions with the disabled element are blocked by a dummy click handler. This is an internal markup change; developers should continue to use the disabled
prop.
This change might break tests that use @testing-library/jest-dom
's toBeDisabled
, toBeEnabled
and toHaveAttribute
matchers. Replace toHaveAttribute('disabled')
with toBeDisabled()
and not.toHaveAttribute('disabled')
with toBeEnabled()
, then extend the matchers to account for the aria-disabled
attribute:
Custom Jest matcher
// jest.setup.js
import { toBeDisabled, toBeEnabled } from '@testing-library/jest-dom/matchers';
function isAriaDisabled(element) {
return (
element.hasAttribute('aria-disabled') &&
element.getAttribute('aria-disabled') === 'true'
);
}
expect.extend({
toBeDisabled(element) {
const isDisabled =
toBeDisabled.bind(this)(element).pass || isAriaDisabled(element);
return {
pass: isDisabled,
message: () => {
const is = isDisabled ? 'is' : 'is not';
return [
this.utils.matcherHint(
`${this.isNot ? '.not' : ''}.toBeDisabled`,
'element',
''
),
'',
`Received element ${is} disabled:`,
` ${this.utils.printReceived(element.cloneNode(false))}`,
].join('\n');
},
};
},
toBeEnabled(element) {
const isEnabled =
toBeEnabled.bind(this)(element).pass || !isAriaDisabled(element);
return {
pass: isEnabled,
message: () => {
const is = isEnabled ? 'is' : 'is not';
return [
this.utils.matcherHint(
`${this.isNot ? '.not' : ''}.toBeEnabled`,
'element',
''
),
'',
`Received element ${is} enabled:`,
` ${this.utils.printReceived(element.cloneNode(false))}`,
].join('\n');
},
};
},
});
SumUp is changing its brand colors from blue to black & white. The color tokens exported by @sumup/design-tokens
have been updated accordingly.
The color tokens have been removed from the legacy JavaScript theme object and theme prop type. Use the semantic color tokens instead:
-color: ${theme.colors.p500};
+color: var(--cui-fg-accent);
- Removed the legacy navigation components: Header, Sidebar, SidebarContextProvider and SidebarContextConsumer. Use the TopNavigation and SideNavigation components instead (π€ no-deprecated-components)
- Removed the deprecated
variant
prop from the ProgressBar component (π€ no-deprecated-props)
- Deprecated the ButtonGroup's
actions.[primary|secondary].size
prop. Use the top-levelsize
prop instead. - Replaced the NotificationBanner's "tertiary" action variant with the "secondary" one and changed the action size to medium. Update the action props if necessary.
- Changed the NotificationInline's action from the Button to the Anchor component. Update the action props if necessary.
- Changed the variant of the previous/next buttons in the Pagination component from "tertiary" to "secondary".
- Changed the default size of the CloseButton from 40px to 48px to match the Button component.
Circuit UI v7 contains two foundational changes β the switch to ES Modules and the replacement of Emotion.js with CSS Modules β and a number of smaller changes to improve consistency and accessibility. New component lifecycle stages lower the barrier for contributions. The Next.js template has been upgraded to Circuit UI v7 and a new Remix template has been added.
To get started, upgrade @sumup/circuit-ui
and its peer dependencies:
npm upgrade @sumup/circuit-ui @sumup/design-tokens @sumup/icons
Upgrade any linter plugins your app is using:
# ESLint
npm upgrade @sumup/eslint-plugin-circuit-ui
# Stylelint
npm upgrade @sumup/stylelint-plugin-circuit-ui
If you are using Emotion.js in your app or are importing legacy components, update all Emotion.js-related dependencies:
npm upgrade @emotion/is-prop-valid @emotion/react @emotion/styled
For a complete list of changes, refer to the changelog.
Circuit UI now relies on APIs introduced in React 18. Upgrade the react
and react-dom
peer dependencies to >=18.
Circuit UI now requires at minimum Node.js v18. Note that Node 16 is scheduled to reach its end-of-life in September 2023.
Circuit UI no longer supports a range of older browsers:
Browser | Previous | New |
---|---|---|
Chrome | 63+ | 73+ |
Firefox | 67+ | 67+ |
Edge | 79+ | 79+ |
Safari iOS | 11.0+ | 12.2+ |
Safari macOS | 11.1+ | 12.1+ |
Opera | 50+ | 60+ |
Samsung Internet | 8.2+ | 11.1+ |
As of ES6 (ES2015), JavaScript supports a native module format called ES Modules, or ECMAScript Modules. This modern module format replaces the non-standard CommonJS.
@sumup/circuit-ui
and @sumup/icons
are now pure ESM. Please read this.
- If you use TypeScript, you need to use TypeScript 4.7 or later (ref).
- If you use a bundler, make sure it supports ESM and that you have correctly configured it for ESM. (Next.js supports ESM packages out of the box since v12).
- The
"exports"
field is now used to configure the package entry points. Files that are not explicitly defined in"exports"
can no longer be imported.
Emotion.js, the CSS-in-JS library that Circuit UI had used until now to style components, has been replaced with CSS Modules. This will significantly improve the performance of SumUpβs web applications, future-proof the component library against ecosystem changes and start to decouple it from React. Read more about the reasoning in the RFC.
Remove the BaseStyles
component and import the CSS files containing the light theme and component styles instead:
// _app.tsx
import { ThemeProvider } from '@emotion/react';
import { light } from '@sumup/design-tokens';
-import { BaseStyles } from '@sumup/circuit-ui';
+import '@sumup/design-tokens/light.css';
+import '@sumup/circuit-ui/styles.css';
function App({ Component, pageProps }) {
return (
<ThemeProvider theme={light}>
- <BaseStyles />
<Component {...pageProps} />
</ThemeProvider>
);
}
The application code must be processed by a bundler that can handle CSS files. Next.js, Create React App, Remix, Vite, Parcel and others support importing CSS files out of the box.
If you are only importing stable components and aren't using Emotion.js in your app, you can remove all Emotion.js-related dependencies.
You can continue to pass the className
and styles
props to Circuit UI components. If your application uses Emotion.js, you can continue to use the css
prop since it is transpiled to the className
prop by Emotion.jsβ Babel plugin.
The design tokens have been ported to CSS custom properties (aka CSS variables) similar to the existing semantic color tokens:
-${theme.borderRadius.circle}
+var(--cui-border-radius.circle)
The JavaScript theme
object from @sumup/design-tokens
has been deprecated. Use the π€ prefer-custom-properties
ESLint rule to flag and automatically rewrite uses of the JS theme to CSS custom properties.
Note that some theme properties haven't been migrated to CSS custom properties and are considered legacy:
mq
andbreakpoints
: Unfortunately, CSS custom properties aren't supported inside media queries. In the future, we might be able to use CSS environment variables but they are a long way off. Until then, you can keep using the JS theme properties or hard-code the media queries.grid
: These properties were only intended to be used by the Grid components. Remove any usage of them.
Circuit UI exports style mixins such as spacing
, hideVisually
, or shadow
. These functions return an Emotion.js style object that can be passed to the css
prop but not the className
prop. The legacy style mixins will be kept for backward compatibility.
For applications that donβt use Emotion.js, Circuit UI exports a new, smaller collection of string utility classes that can be passed to the className
prop and conditionally joined using the new clsx
helper.
Example
import { clsx, utilClasses } from '@sumup/circuit-ui';
function Component() {
return <div className={clsx(utilClasses.center, utilClasses.hideVisually)} />;
}
Circuit UI v7 introduces the concept of lifecycle stages for components. Within each stage, components meet different requirements and receive different levels of support. Experimental and legacy components are exported separately from stable components. Use the π€ component-lifecycle-imports
ESLint rule to flag components that have moved to a different stage and automatically update their imports.
The following components have been moved to the legacy stage:
- Layout components: Grid, Row, Col, and InlineElements
- Calendar components: CalendarTag, CalendarTagTwoStep, RangePicker, RangePickerController, SingleDayPicker, and CalendarConstants
- Legacy navigation components: Header, Sidebar, SidebarContextProvider, and SidebarContextConsumer
- Tooltip component
- Style mixins:
cx
,center
,clearfix
,disableVisually
,focusOutline
,focusVisible
,hideScrollbar
,hideVisually
,inputOutline
,shadow
,spacing
, andtypography
- The
uniqueId
utility function
@sumup/collector
has been deprecated and the integration with Circuit UI has been removed. Replace the tracking
prop with event handlers to dispatch user interaction events instead (π€ no-deprecated-props
).
import { Button } from '@sumup/circuit-ui';
+import { useClickTrigger } from '@sumup/collector';
function Component() {
+ const dispatch = useClickTrigger();
+
+ const handleClick = () => {
+ dispatch({
+ component: 'button',
+ label: 'track-button',
+ customParameters: { key: 'value' },
+ });
+ // ...other logic
+ }
return (
<Button
+ onClick={handleClick}
- tracking={{
- label: 'track-button',
- customParameters: { key: 'value' },
- }}
>
Buy now
</Button>
);
}
Removed the public export of the RadioButton component. Use the RadioButtonGroup component insteadReverted in v7.1 and postponed until v9 (π€no-deprecated-components
)Removed the public export of the Selector component. Use the SelectorGroup component insteadReverted in v7.1 and postponed until v9 (π€no-deprecated-components
)- Removed the deprecated
children
property from the SelectorGroup'soptions
prop. Use thelabel
anddescription
properties instead. - Removed the deprecated
children
prop from the Checkbox component. Use thelabel
prop instead. - Removed the deprecated
explanation
prop from the Toggle component. Use thedescription
prop instead (π€no-renamed-props
) - Removed the deprecated
confirm
,notify
, andalert
variants from the Badge, NotificationInline, and NotificationToast components. Use thesuccess
,warning
, anddanger
variants instead (π€no-renamed-props
) - Changed the signature of the ImageInput's
component
prop. The component should now acceptaria-hidden
instead ofalt
. - Migrated the Calendar components to TypeScript. Some props are now required. The CalendarTagTwoStep's
clearText
andconfirmText
props have been renamed toclearButtonLabel
andconfirmButtonLabel
respectively. - Migrated the Carousel components to TypeScript. Added the required
playButtonLabel
,pauseButtonLabel
,prevButtonLabel
, andnextButtonLabel
props. - Migrated the Tabs and Sidebar components to TypeScript.
- Simplified the function signature of the style mixins that no longer require the theme parameter (
shadow
,focusOutline
,focusVisible
, andinputOutline
). - Removed the
sharedPropTypes
export. Type the props using TypeScript instead.
- Circuit UI v7 is incompatible with
next-plugin-preact
because the plugin breaks support for ES Modules.
Although not a major version, Circuit UI v6.3 comes with a few important visual changes related to color that we wanted to mention here for visibility.
To get started, upgrade @sumup/circuit-ui
and @sumup/design-tokens
:
yarn upgrade @sumup/circuit-ui @sumup/design-tokens --latest
In v6.1, we released new semantic color tokens, which are meant to replace the existing color tokens from @sumup/design-tokens
to enable use cases like theming, as well as more robust customizations. The new tokens were declared as CSS custom properties in the Circuit UI BaseStyles
.
Starting in v6.3, all Circuit UI components (except the legacy Sidebar
component) use these semantic color tokens under the hood. Legacy color tokens from @sumup/design-tokens
have been deprecated and will be removed in a future major version.
A number of components were adjusted to the new color system. Most notably:
- The
Avatar
component's default placeholder (visible when nosrc
is passed) was changed to match the new colors and to use SVG icons from@sumup/icons
. - All form components
validationHint
s, in their warning state, are now orange instead of gray. - Warning icons are now orange on white, instead of yellow with a black exclamation mark
!
. - The warning color changed from yellow (2.01:1 contrast ratio) to orange (3.01:1 contrast ratio).
- The
Button
component's disabled state styles were visually aligned with iOS and Android styles. Contrast is now effectively lower.
- We've received a report that the upgrade surfaced a long-standing JSDOM bug where a
<fieldset>
element is considered:disabled
if it contains a<legend>
. This might cause issues with unit tests that useuser-event
, since it will throw when trying to interact with a:disabled
element. This is seemingly unrelated to Circuit UI, but if you run into the issue, you can work around it by turning offuser-event
'spointerEventsCheck
:userEvent.click(element, { pointerEventsCheck: 0 }
.
Circuit UI v6 contains two major changes: the removal of default component margins, and changes to form components to improve consistency and accessibility.
To get started, upgrade @sumup/circuit-ui
and its peer dependencies:
yarn upgrade @sumup/circuit-ui @sumup/design-tokens @sumup/icons --latest
For a complete list of changes, refer to the changelog.
β οΈ Note: this major version doesn't include codemods. The changes cannot easily be automated and should be migrated manually. Detailed migration steps for each change are listed below.
Default component margins have been deprecated since v2, and the use of the noMargin
prop was encouraged to ensure that UIs don't rely on the default margin. Omitting the prop throws errors since v5.
In v6, default margins have been completely removed from components. The noMargin
prop, now redundant, has been removed as well.
If you've already addressed all the errors thrown in v5, migration is straightforward: now that the noMargin
prop isn't necessary anymore, you can simply remove it from your codebase. If you haven't, make sure to address them before migrating to v6. Failure to do so can result in unintended UI bugs.
Removing the prop from your codebase is easiest done using search and replace in your IDE.
In v6, form components follow a more consistent and accessible pattern.
Markup was adapted to improve consistency and accessibility across form components.
- Form components are now all wrapped in a
div
that receives any styles passed through thestyle
orclassName
attributes, including via the Emotion.jscss
prop. This might break custom styles. - Form
<label>
s don't wrap inputs anymore. This might break styles previously passed tolabelStyles
(see also ThelabelStyles
prop was removed). - An empty live region is now rendered below form components. If a
validationHint
is passed along with either theinvalid
,hasWarning
orshowValid
props (indicating status messages), the message will be rendered inside the live region to be announced by screen readers. - The
validationHint
is now programmatically associated to a form control viaaria-describedby
. A uniqueid
for it is generated internally. If a customid
is passed to a component witharia-describedby
, the descriptions will be combined.
Verify your forms visually. Look out for form components with custom styles and adapt them as needed.
In most cases, the Label
component shouldn't be used: form components have a built-in label
prop that ensures that controls are appropriately and accessibly labelled.
In implementations where the Label
doesn't label a form component, use a <Body size="two" />
instead.
Where the Label
describes the purpose of a form component, use the built-in label
prop instead. In edge cases and custom form component implementations, replace the Label
by a <label css={typography("two")} />
.
The prop was removed from the Input
, TextArea
and Select
components.
It went again the principles of atomic design and was rarely used in implementations.
Replace it with a custom CSS wrapper, for example using display: flex;
.
Alternatively, to recreate the exact same functionality, pass display: inline-block;
and a margin to the components:
const inlineStyles = (theme) => css`
display: inline-block;
margin-right: ${theme.spacings.mega};
`;
function Address() {
return (
<>
<Input label="Postcode" css={inlineStyles} />
<Input label="City" css={inlineStyles} />
</>
);
}
The prop was removed from the Input
and TextArea
components.
In v5, labelStyles
is predominantly used to apply styles to a form component's wrapper, the label
element. Wrapper styles can't be passed via the style
or className
prop, because these are forwarded to the underlying form element.
In v6, form components are wrapped in a div
that receives any style
or className
props, including via the Emotion.js css
prop.
Therefore, to migrate:
labelStyles
should be replaced by the Emotion.jscss
propcss
(previously passed to the underlying form element) should be replaced byinputStyles
For example:
<Input
label="Name"
/* wrapper styles */
- labelStyles={spacing({ bottom: "giga" })}
+ css={spacing({ bottom: "giga" })}
/* input styles */
- css={customInputStyles}
+ inputStyles={customInputStyles}
/>
Note that if you were using the labelStyles
in non-standard ways (for example using selectors such as > div
to style component internals), you may need to refactor your implementation.
In v5, some form components (such as the Input
) accepted any ReactNode
as a label.
This can be an accessibility issue, because the label
prop value is exposed to assistive technology as the control's accessible name. Accessible names don't have semantics or structure, so rendering e.g. an anchor or a tooltip in the label
is bad practice.
In v6, the label
prop only accepts a string
. The change is TypeScript-only (i.e. a ReactNode
would still be rendered) but migration is encouraged.
We've observed two common patterns affected by this change:
If a label
is used to render an optional label, it can be replaced with the optionalLabel
prop:
- const optionalStyles = (theme) => css`
- color: ${theme.colors.n700};
- `;
<Input
- label={<>Address line 2 <span css={optionalStyles}>(Optional)</span></>}
+ label="Address line 2"
+ optionalLabel="Optional"
/>;
If a label
is used to render a tooltip next to the label, replace the tooltip with a validationHint
.
If you need time to migrate, you can temporarily ignore the change (with @ts-expect-error
if using TypeScript). Bear in mind that passing a ReactNode
may stop working in a future minor.
In v5, a validationHint
passed to the Checkbox
component (either as a description or as a status message) would render in a tooltip.
This caused accessibility and UI issues (with the tooltip overlapping other controls) and wasn't consistent with other form components.
In v6, a validationHint
is rendered below the Checkbox
.
This version also includes a number of accessibility and visual fixes. While these aren't technically breaking changes, you may notice them in snapshots, so they are listed here for your convenience:
- the
RadioButtonGroup
's role was changed from the implicitgroup
(from thefieldset
element) to the explicitradiogroup
. It also hasorientation="vertical"
- the chevron icon in the
Select
element was hidden from assistive technology usingaria-hidden
- invalid radio buttons are now programmatically marked as invalid using
aria-invalid
- the
CurrencyInput
's currency code/symbol is now exposed to assistive technology as part of the input's description - the font size of any text rendered in an
Input
's prefix or suffix was increased from 14px to 16px to match designs. This also affects theCurrencyInput
's currency code/symbol. - unintended spacing was removed from below the
TextArea
usingvertical-align: top;
react-number-format
was upgraded to v5. This could be a breaking change if you were relying on internalreact-number-format
props. Refer to thereact-number-format
migration guide for details. Any explicit typings will also need to be updated.- The
ButtonGroup
component now switches between a secondary button (on viewports of at leastmq.kilo
) and a tertiary button (on viewports narrower thanmq.kilo
) using CSS media queries, instead of rendering three buttons and conditionally hiding one. Tests (e.g. using@testing-library
) should now query the secondary button without using*AllBy
queries. Snapshots might also be affected. - Typography design tokens now use the
rem
unit. Ensure that your global styles do not override the root font-size. See The Surprising Truth About Pixels and Accessibility. - The
Popover
component was migrated from Popper (deprecated) to Floating UI. If your app uses Popper directly, we recommend migrating to Floating UI to avoid duplicating dependencies. See Migrating from Popper 2 to Floating UI - Circuit UI's browser support policy was updated. The library now supports browsers with support for dynamic module imports. See the Browser Support documentation for details.
- If your app uses TypeScript, an upgrade of the
@types/react
package in Circuit UI may clash with the version installed in your app. If your app is on React 18, upgrade@types/react
to^18.0.25
to fix the issue. If your app is on React 17, upgrade@types/react
to^17.0.52
and extend the React namespace. More details on the DefinitelyTyped PR that introduced the issue.
Some of the changes up to v5 can be automated with codemods, small scripts that modify your app's source code automatically. Changes that can be codemodded are marked with a robot emoji (π€) and the name of the transform (e.g. button-variant-enum). The codemods are built with jscodeshift and can be run through the CLI that ships with Circuit UI. Here is an overview of all available options (you can view this help menu by running yarn circuit-ui migrate --help
):
yarn circuit-ui migrate
Automatically transforms your source code to Circuit UI's latest APIs
Options:
--language, -l The programming language(s) of the files to be transformed
[array] [required] [choices: "TypeScript", "JavaScript", "Flow"]
--path, -p A path to the folder that contains the files to be
transformed [string] [default: "."]
--transform, -t The transform to be applied to the source code
[string] [required] [choices: "button-variant-enum", ...]
You can only run one codemod at a time and we encourage you to apply the transforms incrementally and review the changes before continuing. The codemods don't cover all edge cases, so further manual changes might be necessary. For example, jscodeshift
is only able to look at one file at a time, so if a Circuit UI component is wrapped in a styled component in one file and used in another, the codemod won't be able to update its props.
Tip: Provide the --transform
/-t
argument at the end of the command, so that as you run further codemods you can easily replace the last argument and reuse the command to run the next codemod.
β οΈ If you run into'node\r': No such file or directory
when running the codemods with yarn, run them with Node directly instead (this is a known issue)../node_modules/.bin/circuit-ui migrate -l JavaScript -l TypeScript -t codemod-name
Circuit UI v5 is a maintenance release, primarily removing deprecated components and props.
β οΈ In order to make the migration from v4 to v5 easier, we recommend that you address the changes listed below before upgrading the Circuit UI dependencies. Deprecation warnings can also help identify code that needs to be migrated.
Starting in v5, Circuit UI is explicit about which browsers it supports. Refer to the browser support documentation for details.
Here's what you need to be mindful of when migrating:
- You no longer need to transpile Circuit UI when bundling your application (using e.g.
next-transpile-module
in Next.js). Circuit UI now supports all target browsers out-of-the-box. - Previously recommended polyfills for Internet Explorer support are no longer necessary, and can be removed from your application:
- the polyfill for the
Intl.NumberFormat
API isn't necessary anymore. - the
object-fit
polyfill (for the Carousel component) isn't necessary anymore.
- the polyfill for the
New semantic color names were introduced in @sumup/design-tokens@3.4.0
. The legacy names were deprecated and have been removed in v5.
Legacy name | New name |
---|---|
success |
confirm |
warning |
notify |
danger |
alert |
The new naming brings cross-platform consistency, as well as alignment with some existing components such as the notification icons.
π€ semantic-color-names
Some Body
, BodyLarge
and Badge
component variants were also renamed for consistency with the new design tokens:
Legacy variant | New variant |
---|---|
<Body variant="success" /> |
<Body variant="confirm" /> |
<Body variant="error" /> |
<Body variant="alert" /> |
<Badge variant="success" /> |
<Badge variant="confirm" /> |
<Badge variant="warning" /> |
<Badge variant="notify" /> |
<Badge variant="danger" /> |
<Badge variant="alert" /> |
Note: the Body
variants mapping above also apply to the BodyLarge
component.
The legacy variant names were deprecated in v4.14.0 and will be removed in v5.
π€ semantic-variant-names
The legacy Circuit UI notification components (Notification
, NotificationList
, NotificationCard
and InlineMessage
) were general purpose and lacking clear guidelines on when to use which, leading to inconsistent usage in our apps.
They were deprecated in v4.14.0 and replaced by semantic, accessible components that make it clear when each should be used and are flexible enough to cover all use cases (NotificationBanner
, NotificationFullscreen
, NotificationModal
, NotificationToast
and NotificationInline
). The legacy components have been removed in v5.
To migrate to the new notifications, you'll need to:
- Replace the
InlineMessage
by theNotificationInline
in your app - Replace uses of the
NotificationCard
,NotificationList
andNotification
(often used together) by either theNotificationInline
orNotificationBanner
, depending on the use cases.
Furthermore, some patterns that were previously not supported by Circuit UI are now available:
- The new
NotificationToast
provider and hook should replace any custom implementation of a toast notifications system for improved accessibility. - The new
NotificationModal
can be used for building notification dialogs that are essential to user flows. - The new
NotificationFullscreen
can replace custom full-screen messages such as error pages or empty states, for more consistency across pages.
Read more about the new notification components in the Notification section in Storybook.
In Circuit UI v3, components requiring accessible labels started throwing an error when the labels weren't being passed. This behavior could be worked around for migration purposes by setting the UNSAFE_DISABLE_ACCESSIBILITY_ERRORS
environment variable.
In v5, the workaround was removed, meaning that all components that require accessible labels expect to receive them.
Before migrating, make sure that you add appropriate and localized labels for all occurrences flagged by the error mechanism. After that, stop setting the UNSAFE_DISABLE_ACCESSIBILITY_ERRORS
environment variable.
Several components used to have built-in bottom margin by default, and a noMargin
prop to reset it. This non-atomic behavior was deprecated several major versions ago, but migration has proved difficult.
All components with built-in margin should be passed noMargin
, so that we can remove the prop using codemods in a future major while avoiding UI regressions.
Instead of removing the noMargin
prop in v5, components that should receive it now throw a runtime error in development if the prop is missing. Production and testing builds are not affected. The noMargin
prop was also marked as required in TypeScript types.
While migrating, you can use an escape hatch to continue running your app in development without throwing.
In your app, expose the UNSAFE_DISABLE_NO_MARGIN_ERRORS
environment variable. You can use the Webpack DefinePlugin
(see the Circuit UI Storybook Webpack config as an example) or, if your app uses Next.js, you can declare the variable in your next.config.js
(Next.js documentation).
Once your app is set up to accept the environment variable, set it to true
in development to prevent components from throwing:
UNSAFE_DISABLE_NO_MARGIN_ERRORS=true yarn dev # or yarn start
Keep in mind that this escape hatch is not meant as a way to permanently bypass the errors, but as a temporary workaround to help migrate without regressions. The noMargin
prop will be entirely removed in v6.
Two new components, ListItem
and ListItemGroup
, were added to Circuit UI v4.4.0 to render lists of contextually similar items.
The ListItem
component should generally be used implicitly by passing items
to the ListItemGroup
. The ListItemGroup
differs from the List
component because while the latter applies light styling to an HTML ul
or ol
, the former allows for structured data and interactivity. Refer to the component's documentation for usage guidelines and examples.
Circuit UI v5 comes with two related breaking changes:
- the legacy
CardList
component has been deprecated in favor of theListItemGroup
. The component APIs are very different and migration can unfortunately not be automated: please migrate manually. The new component also comes with different styles: verify the changes visually with a designer. - (If you were already using the
ListItem
in a Circuit UI v4.x release:) TheListItem
component'sprefix
andsuffix
props were renamed toleadingComponent
andtrailingComponent
. ThesuffixLabel
andsuffixDetails
props were renamed totrailingLabel
andtrailingDetails
. The codemod will not transform uses of theListItem
asListItemGroup
items. (π€ listitem-prop-names)
The LoadingButton
is an extension of the Button
component and adds a loading state. This is a common use case, so the loading functionality has been added to the Button
component itself. The LoadingButton
was deprecated in v4.1 and was removed in v5.
The API hasn't changed: uses of the LoadingButton
can be replaced by the Button
component
π€ component-names-v5
- The deprecated
zIndex.sidebar
design token was removed from@sumup/design-tokens
. UsesIndex.navigation
instead. There is no codemod for this change: search and replace the old value for the new one in your codebase. - The deprecated
shadowSingle
,shadowDouble
andshadowTriple
style mixins were removed. Use theshadow()
style mixin instead. There is no codemod for this change: migrate manually by searching for the deprecated style mixins in your codebase, and verify the changes visually. - The
RadioButton
component's deprecatedchildren
prop was removed. Use thelabel
prop, now typed as required, instead. There is no codemod for this change: search your codebase for uses of theRadioButton
orRadioButtonGroup
component and migrate them manually. - The
ButtonGroup
component's deprecatedchildren
prop was removed. Use theactions
prop instead. If the newButtonGroup
component API doesn't fit your use case, consider aligning your use case with the design system, or writing a custom layout wrapper for your buttons. - The deprecated
showValid
option was removed from theinputOutline
style mixin.
Circuit v4 is a small maintenance release, featuring the upgrade to Emotion 11 and new brand icons.
To get started, upgrade @sumup/circuit-ui
and its peer dependencies:
yarn upgrade @sumup/circuit-ui @sumup/design-tokens @sumup/icons --latest
For a complete list of changes, refer to the changelog.
Circuit was upgraded to Emotion 11, so apps using Circuit will also have to upgrade. The main changes are Emotion's new package names and better TypeScript support.
The main change in Emotion 11 is a renaming of most packages under the @emotion
organization.
It can be automated by using an ESLint plugin provided by Emotion: refer to the migration guide for upgrade instructions.
Then, after running the codemod:
- Remove the legacy dependencies and add the new ones:
# example with yarn yarn remove @emotion/core jest-emotion babel-plugin-emotion # remove legacy dependencies yarn add @emotion/react # add new dependencies yarn add -D @emotion/babel-plugin @emotion/jest # add new dev dependencies yarn upgrade @emotion/styled --latest # upgrade existing packages
- Fix any duplicate imports of
@emotion/react
in cases where multiple modules (e.g.css
from v10's@emotion/core
andThemeProvider
from v10'semotion-theming
) are all under@emotion/react
in v11.
Emotion's TypeScript types have been improved in v11. Refer to the migration guide for details of the changes.
One of the most useful changes is support for typing the theme.
Previously, many apps would use CreateStyled
:
// utils/styled.ts
import styled, { CreateStyled } from '@emotion/styled';
import { Theme } from '@sumup/design-tokens';
export default styled as CreateStyled<Theme>;
...and import the custom styled
in their components:
// components/RedCard.tsx
import { css } from '@emotion/core';
import styled from 'util/styled';
const RedCard = styled(Card)(
({ theme }) => css`
background-color: red;
`
);
Now, you can type the theme by adding it to @emotion/react
's declaration:
// types/emotion.d.ts (don't forget to include this file in tsconfig.json under `typeRoots`)
import { Theme as CircuitTheme } from '@sumup/design-tokens';
import {} from '@emotion/react/types/css-prop'; // See https://github.com/emotion-js/emotion/pull/1941
declare module '@emotion/react' {
export interface Theme extends CircuitTheme {}
}
...and use styled
from @emotion/styled
directly:
// components/RedCard.tsx
import { css } from '@emotion/core';
import styled from '@emotion/styled';
const RedCard = styled(Card)(
({ theme }) => css`
background-color: red;
`
);
In case you're using Storybook in your application, you'll need to tweak the Storybook Webpack config to make it compatible with Emotion 11 (Storybook is still on Emotion 10).
Make sure that references to Emotion packages inside Storybook are pointing to the v11 packages:
// .storybook/main.js
const path = require('path');
const toPath = (_path) => path.join(process.cwd(), _path);
module.exports = {
webpackFinal: async (config) => {
// Add compatibility with Emotion 11
config.resolve.alias = {
...config.resolve.alias,
'@emotion/core': toPath('node_modules/@emotion/react'),
'@emotion/styled': toPath('node_modules/@emotion/styled'),
'emotion-theming': toPath('node_modules/@emotion/react'),
};
return config;
},
};
Circuit v4 ships with the new brand icons from @sumup/icons
v2.
- There used to be "filled" and "empty" versions of some of the v1 icons. The distinction has been removed and all icons are now using a "filled" design. The icon versions were primarily used in the legacy
Sidebar
component, which is being replaced by the newSideNavgation
. - The icons' size names changed from
small
andlarge
to16
and24
(their size in pixels). - The default icon size was
small
in v1 but is now24
in v2 (this change follows Circuit v3's new component heights). - Many icons were renamed.
- Some icons or icon sizes were removed.
Most of the changes can be automated using the π€ icons-v2 codemod.
The codemod will print warnings and errors to your console when a manual migration is required:
- Some icons were renamed to match the names of SumUp products. They should not be used outside of the product's context. If you have doubts about your use of the icon, file an issue or contact the Design System team.
- If an icon you were using was removed in v2 and can't be replaced by another icon, file an issue or contact the Design System team.
- If you were using a
small
(16px) icon that is only available in v2 in24
(24px), see if the 24px size works for your use case. If it doesn't, file an issue or contact the Design System team.
Finally, remember to visually verify your application after the upgrade!
Circuit v3 is a large major release, including long-awaited changes from the full year that passed since v2. This guide will help you upgrade your application. Don't hesitate to contact the maintainers if you have any further questions.
Start by upgrading @sumup/circuit-ui
and its peer dependencies:
yarn upgrade @sumup/circuit-ui @sumup/design-tokens @sumup/icons --latest
Any accessible label props that were previously optional are now required and enforced in all components.
To help identify places where accessible labels are missing, components throw runtime errors in development at missing labels. Production and testing builds are not affected.
During the migration and while the missing labels are still being added, you can use an escape hatch to continue running the app in development without throwing accessibility errors.
In your app, expose the UNSAFE_DISABLE_ACCESSIBILITY_ERRORS
environment variable. You can use the Webpack DefinePlugin
(here's an example in the Circuit UI Storybook config) or, if your app uses Next.js, you can declare the variable in your next.config.js
(Next.js documentation).
Now, if you want to turn off the accessibility errors temporarily, run the development app with the environment variable set to true
:
UNSAFE_DISABLE_ACCESSIBILITY_ERRORS=true yarn dev # or yarn start
Keep in mind that this escape hatch is not meant as a way to permanently avoid the errors, but as a temporary workaround while the missing labels are being written, localized and added to the relevant components.
Reminder: For the
Input
andSelect
components, use the built-inlabel
prop instead of using theLabel
component separately.
Other accessibility improvements include:
- Accessible modals and popovers: see the New modal and popover APIs.
- Semantic heading elements: see Typography: Heading
as
props.
Circuit v3 improves compatibility with the new JSX transforms (introduced in React v17).
We recommend the following Babel config for applications on Next.js and Emotion 10 (Emotion 11 is not yet supported by Circuit UI). It also includes support for Emotion's css
prop.
{
"presets": [
[
"next/babel",
{
"preset-react": {
"runtime": "automatic",
"importSource": "@emotion/core"
}
}
]
],
"plugins": [["babel-plugin-emotion", { "cssPropOptimization": true }]]
}
Before v3, typography components were general purpose and flexible. There were no guidelines on when to use a certain typography style. This has led to inconsistent usage in our apps.
The new version introduces new, semantic typography components that make it clear when each should be used, are flexible enough to cover all use cases, and for the first time include semantic colors as well.
The core typography components were renamed:
v2 | v3 |
---|---|
Text |
Body |
Heading |
Headline |
SubHeading |
SubHeadline |
Blockquote |
See the next section |
(π€ component-names-v3.)
Note that the codemod will also transform other renamed components (see Other Changes.
The Body
(formerly Text
) component's variants were changed:
v2 | v3 |
---|---|
<Text bold> |
<Body variant="highlight"> |
<Text italic> |
Use custom styles |
<Text strike> |
Use custom styles |
<Blockquote> |
<Body variant="quote"> |
β οΈ These changes also apply to theAnchor
component, which extendsBody
.
Use π€ body-variant-highlight to migrate bold
to variant="highlight"
. Note that this will transform your <p>
elements into inline <strong>
elements: you might also need to pass as="p"
if you need a block-level element.
Bonus: the new
Body
component also supports thesuccess
,error
andsubtle
semantic variants. Have a look at the story to get started.
The number of available sizes was reduced, and size names were changed from the metric prefix scale (kilo
, mega
etc.) to numbers (one
, two
etc.).
The number of sizes was reduced in v3, here's the desired mapping from v2:
v2 | v3 |
---|---|
<Heading size="kilo"> |
<Headline size="four"> |
<Heading size="mega"> |
<Headline size="four"> |
<Heading size="giga"> |
<Headline size="three"> |
<Heading size="tera"> |
<Headline size="two"> |
<Heading size="peta"> |
<Headline size="one"> |
<Heading size="exa"> |
<Headline size="one"> |
<Heading size="zetta"> |
Migrate manually to size="one" or use custom styles (2.625rem) |
<SubHeading size="kilo"> |
<SubHeadline> (the sizes were removed) |
<SubHeading size="mega"> |
<SubHeadline> (the sizes were removed) |
<Text size="kilo"> |
<Body size="two"> |
<Text size="mega"> |
<Body size="one"> |
<Text size="giga"> |
Migrate manually to size="one" or use custom styles (1.125rem) |
β οΈ TheBody
size changes also apply to theAnchor
andList
components.
Most of these changes can be automated using the π€ typography-sizes codemod.
The codemod will also warn about occurrences of <Heading size="zetta">
and <Text size="giga">
. These should be manually migrated to size="one"
if possible, or alternatively to custom size styles (recommendation from design: 2.625rem for the Headline
and 1.125rem for the Body
).
The deprecated text[Kilo|Mega|Giga]
style mixins were replaced by a single typography
mixin, and the deprecated heading[Kilo|Mega|Giga|Tera|Peta|Exa|Zetta]
and subHeading[Kilo|Mega]
style mixins were removed.
Generally, avoid using typography style mixins. Instead, use typography components directly.
The as
prop is now required in both the Headline and the SubHeadline components. Intentionally setting the heading level ensures a consistent and accessible page structure. The as
prop values were also restricted to HTML heading elements to ensure that heading components render semantic heading elements.
Component | Allowed as prop values |
---|---|
Headline |
h1 , h2 , h3 , h4 , h5 , h6 |
SubHeadline |
h2 , h3 , h4 , h5 , h6 |
Note that the
Headline
andSubHeadline
will still fall back toh2
andh3
, respectively, but omitting theas
prop will start throwing errors in the next major version.
The typography size values in @sumup/design-tokens
were also updated to reflect the changes in @sumup/circuit-ui
.
There is no codemod for these changes, migrate manually through search and replace (e.g. typography.text.mega
π typography.body.one
). Refer to the tables in Typography component names and Typography components size
prop for the correct mappings.
Generally, avoid using typography size tokens. Instead, use typography components directly.
The Modal
and Popover
components were refactored to consolidate their APIs and to improve their accessibility.
The Modal
, ModalWrapper
, ModalHeader
, ModalFooter
, ModalContext
, and ModalConsumer
components are no longer exported. Instead, use the useModal
hook to render modals instead.
Modals in Circuit v3 are accessible by default, have a streamlined UI and behavior (dimensions, click outside, etc.) and handle edge cases like modal and popover stacking.
Refer to the Modal stories for usage examples.
β οΈ You might notice browser UI obscuring parts of your application on mobile viewports. Your application needs to ensure its content stays within CSS safe areas using CSSenv
. See Getting started for help with configuring the viewport.
The Popover
component was rebuilt in Circuit v3. It now uses Popper v2 under the hood and comes with a refreshed component API.
More importantly, the Circuit v3 Popover is opinionated when it comes to its usage pattern. It no longer accepts custom children, unlike v2, but rather a list of actions (links and/or buttons).
To migrate, separate the popovers in your application into two types.
Start by migrating any popover resembling a dropdown menu to the new Circuit v3 Popover. Refer to the Popover story for a usage example.
Most of the remaining popovers with custom children should gradually be migrated to use different UI patterns (for example modals). In the meantime, we recommend creating a local copy of the Circuit v3 Popover in your application that accepts custom children instead of an array of actions. You'll find an example in the SumUp merchant dashboard (private repository).
The heights of all form components were aligned for consistency. The new size values are:
Size name | Value | Usage |
---|---|---|
giga |
48px | Default for web + mobile |
kilo |
32px | Dense layout for web + mobile |
byte |
24px | Extreme dense layout for web + mobile |
Here's an overview of how the component heights have changed:
Component | Old default height | New default height |
---|---|---|
Button and derived components | 40px | 48px |
Input and derived components | 40px | 48px |
Select | 40px | 48px |
Tabs | 80px | 48px |
Tag | 34px | 32px |
We recommend verifying these changes visually at the end of the migration.
In addition to its increased height, the Button
's default size was renamed from mega
to giga
to align it with the new size values (see the table above). (π€ button-default-size)
- The design tokens borderRadius scale was changed. (π€ theme-border-radius)
value v2 name v3 name 1px kilo
β (remove the radius or hardcode) 4px mega
bit
6px giga
β (migrate to byte
)8px tera
byte
12px peta
kilo
16px β mega
(new value) - The NotificationBanner component has been renamed to NotificationCard. (π€ component-names-v3)
- Label prop names across components were harmonized to follow the Label pattern. (π€ label-prop-names)
- CardHeader:
labelCloseButton
πcloseButtonLabel
- Hamburger:
labelActive
πactiveLabel
,labelInActive
πinactiveLabel
- Tag:
labelRemoveButton
πremoveButtonLabel
- Toggle:
labelChecked
πcheckedLabel
,labelUnchecked
πuncheckedLabel
- CardHeader:
- The TableRow, TableHeader and TableCell components are no longer exported. Use the Table component instead.
- The Table's custom
onSortBy
method signature has been changed. ThenextDirection
argument moved to the third position ((index, nextDirection, rows)
π(index, rows, nextDirection)
) and is now optional (i.e. it can beundefined
instead ofnull
in the previous implementation). - The SelectorGroup's
label
is now visible by default, passhideLabel
to hide it visually. Its children are now rendered horizontally by default. - Default
data-testids
are no longer built into the Table and CardHeader components. We recommend querying by role in tests instead to imitate how users interact with our applications.
Finally, Circuit v3 removes previously deprecated and/or unused features and props. These breaking changes may not affect your application if you've already addressed the deprecation warnings in Circuit v2 minors, but we still recommend going through the list of changes below.
- The deprecated Spacing component has been removed. Use the spacing style mixin instead.
- The ProgressBar's deprecated
children
prop has been removed. Use thelabel
prop instead. - The Card's deprecated
shadow
prop has been removed. Shadows have been replaced by a single outline in an earlier minor version. - The deprecated
styleHelpers
aggregate is no longer exported. Import each style mixin directly instead. - The
themePropType
is no longer exported from@sumup/circuit-ui
. Import it from@sumup/design-tokens
instead. - The deprecated withComponents HOC has been removed. Use the useComponents hook instead.
- The Badge's deprecated
onClick
prop has been removed. Badges are not meant to be interactive and should only communicate the status of an element. Use the Tag component for interactive elements instead. - The Badge's deprecated
primary
variant has been removed. Use theneutral
variant instead. - The experimental static styles extraction feature has been removed.
Circuit UI is now compiled with TypeScript instead of Babel (#563, #597). ES and CJS versions are available as before, though this is not something you need to worry about since most bundlers pick the best format that they support automatically based on the main
and module
entries in package.json
.
Note, however, that some modern JavaScript syntax and language features are no longer pretranspiled. Tools such as react-scripts v2+ and Next.js include node_modules
in their transpilation process so Circuit UI works with them out of the box. If you have a custom build process, you should make sure that Circuit UI is transpiled like the rest of your source code.
We recommend testing your application in your oldest supported browsers to verify that it still works.
Circuit UI v1 included React and Emotion dependencies as direct dependencies. This could cause these dependencies to be bundled twice if your application specified a different version of React or Emotion.
Circuit UI v2 moves these dependencies to peer dependencies, so Circuit UI will use whatever version your application specifies (#485). The minimum version of React has been bumped to v16.8+ to support hooks.
If you haven't installed them already, you can do so by running the following command in your terminal:
# With yarn
yarn add react react-dom @emotion/core @emotion/styled emotion-theming
# With npm
npm install --save react-dom @emotion/core @emotion/styled emotion-theming
In Circuit UI v2 some functionality has been extracted into separate packages for easier maintenance. The themes have been moved to @sumup/design-tokens, the icons are available from @sumup/icons, and the number & currency utils have been completely rewritten in @sumup/intl. The new @sumup/collector package is used for event tracking. These packages are marked as required peer dependencies. To install them, run the following command in your terminal:
# With yarn
yarn add @sumup/collector @sumup/design-tokens @sumup/icons @sumup/intl
# With npm
npm install --save @sumup/collector @sumup/design-tokens @sumup/icons @sumup/intl
Refer to the individual packages for documentation on how to use them.
Circuit UI now downloads the Aktiv Grotesk font family in the 400 (regular) and 700 (bold) weights. It uses @font-face
with the font-display
set to swap
, which means a fallback font is shown until the custom fonts have loaded.
You should remove any code in your application that was previously used to load these fonts.
A big theme of this release is consistency.
Any additional props that are passed to a component are now spread on their outermost child element (#553). This is useful for test ids, data attributes, and custom styles using Emotion's styled
function or css
prop.
React ref
s allow you to access the underlying DOM node of a component. All Circuit UI components now forward ref
s to the underlying DOM node (for single node components such as a Button) or to the main interactive DOM node (for composite components such as an Input) (#592).
β οΈ The ability to pass custom styles andref
s is meant as an escape hatch. We strongly recommend avoiding using them as we cannot guarantee that they will be compatible with future changes. Please consider opening an issue or PR to suggest the improvement in Circuit UI instead.
Many components expose their configuration values as static properties. The Text
component, for example, exposes its size options as Text.KILO
, Text.MEGA
, and Text.GIGA
. The purpose of these static properties was to autocomplete the options and prevent typos.
Since Circuit UI is being migrated to TypeScript, the static properties are no longer necessary. VS Code can suggest and autocomplete the options based on the TypeScript types. TypeScript will warn you at build time if you use an unsupported or mistyped value. Furthermore, removing the static properties reduces the bundle size slightly.
Thus, the static properties have been removed from all components. Here's how you can pass a value to a component now:
import { Text } from '@sumup/circuit-ui';
const Hello = () => (
- <Text size={Text.KILO}>Hello</Text>
+ <Text size="kilo">Hello</Text>
);
The affected components are: Badge, Blockquote, Button, ButtonGroup, Card, CardFooter, CardList.Item, Heading, InlineMessage, Input, List, MessageIcon, ModalFooter, NotificationIcon, Popover, ProgressBar, SubHeading, TableHeader, TableCell, Text, TextArea, and Tooltip.
(π€ component-static-properties)
- The SideNav component has been removed. Use the Sidebar component instead.
- The CreditCardDetails, CardNumberInput, NameOnCardInput, SecurityCodeInput, ExpiryDateInput, and the credit card utils have been removed. Use SumUp's card widget instead.
- The CardSchemes and PaymentMethodIcon components have been removed. Use @sumup/icons instead.
- The AutoCompleteInput and AutoCompleteTags components have been removed. You can build them yourself using the SearchInput, Card, and Tag components.
- The MaskedInput and RestrictedInput components have been removed. Use react-text-mask or a similar package directly instead.
- The MessageIcon and MessageButton components have been removed. Use the Notification component's icon and children props instead.
- The Markdown component has been removed. Use markdown-to-jsx or a similar package instead.
- The State component has been removed. Use React's useState hook instead.
- The Picture component has been removed. Use the native HTML
picture
element instead.
- The ListView component has been renamed to CardList (π€ component-names-v2)
- The SvgButton component has been renamed to IconButton (π€ component-names-v2)
- The Message component has been renamed to Notification (π€ component-names-v2)
- The InlineNotification component has been renamed to InlineMessage (π€ component-names-v2)
- The GlobalStyles component has been renamed to BaseStyles (π€ component-names-v2)
- The GlobalStyles component no longer accepts a
custom
prop. Use Emotion's Global component instead. - The Heading, SubHeading, Text, and Input components no longer accept the
element
prop. Emotion 10 introduced the ability to change the HTML element. Use theas
prop instead (π€ as-prop) - The List component's
ordered
prop has been replaced by thevariant
enum prop (π€ list-variant-enum) - The List component's default size is now
mega
to match the Text component. - The Badge component's
color
prop has been renamed tovariant
(π€ badge-variant-enum) - The
primary
andsecondary
Button boolean props have been removed. Use thevariant
enum prop instead (π€ button-variant-enum) - The
plain
Button prop has been removed. Use the new Anchor component or thetertiary
Button variant instead. - The
flat
Button variant has been removed (π€ button-variant-enum) - The
giga
Button size has been removed. Use themega
size (default) instead (π€ button-size-giga) - The LoadingButton's exit animations have been removed. An action's success or error result should be communicated outside the button (π€ exit-animations)
- The Input, TextArea, and Select components have the label built in now. Use the
label
prop to pass in the label content and remove the Label component from your code. Thelabel
prop will become required in the next major version of Circuit UI. - The Input and Textarea components no longer accept
*ClassName
props. Emotion 10 uses style objects instead of class names. Use the*Styles
props instead. ThewrapperStyles
prop has been renamed tolabelStyles
(π€ input-styles-prop). - The Input and Textarea components'
deepRef
prop has been renamed toref
(π€ input-deepref-prop) - The Input and Textarea components no longer have an
optional
state. Add "(optional)" to the label text instead. - The Selector component's
onClick
andselected
props have been renamed toonChange
andchecked
(π€ selector-props). Thevalue
andname
have been added as required props. - The RadioButton, Toggle, and Switch component's
onToggle
prop has been renamed toonChange
(π€ onchange-prop) - The Toggle component's
on
,labelOn
, andlabelOff
props have been renamed tochecked
,labelChecked
, andlabelUnchecked
(π€ toggle-checked-prop). - The IconButton component's dimensions and style have changed. It is now consistent with the Button component.
- The Hamburger component's default size has been increased to match the IconButton component.
- The Hamburger component's
light
prop has been removed. Set the color through CSS instead. - The Spinner component's
dark
prop has been removed. Set the color through CSS instead. - The InlineMessage component's
type
prop has been renamed tovariant
(π€ inline-message-variant-enum) - The Pagination component's
footer
,justify
,align
,perPage
, andpagesToShow
props have been removed. Thepage
prop has been renamed tocurrentPage
. Thetotal
prop has been replaced by thetotalPages
prop which represents the total number of pages as opposed to the total number of items (totalPages = Math.ceil(total / perPage)
).
- The
currencyAmountUtils
have been removed. There is no replacement, we suggest you copy the old implementation to your application. - The
currencyUtils
have been removed. Use @sumup/intl instead (π€ currency-utils) - The
textTera
style helper has been removed. Use thetextGiga
style helper instead. - The
shadowGround
andshadowBorder
style helpers have been removed. Use thebox-shadow
CSS property instead. - The unit style helpers (
addUnit
,subtractUnit
,multiplyUnit
,divideUnit
) have been removed. Use the CSScalc
function instead.
- The themes have been moved to @sumup/design-tokens. Import them from there instead (π€ theme-to-design-tokens)
- The
iconSizes.byte
theme value has been removed. UseiconSizes.kilo
instead (π€ theme-icon-sizes) - The
grid.afterTera
theme value has been renamed togrid.tera
(π€ theme-grid-tera)