Some checks failed
No response / noResponse (push) Has been cancelled
CI / Continuous releases (push) Has been cancelled
CI / test-dev (macos-latest) (push) Has been cancelled
CI / test-dev (ubuntu-latest) (push) Has been cancelled
CI / test-dev (windows-latest) (push) Has been cancelled
Maintenance / main (push) Has been cancelled
Scorecards supply-chain security / Scorecards analysis (push) Has been cancelled
CodeQL / Analyze (push) Has been cancelled
589 lines
19 KiB
Markdown
589 lines
19 KiB
Markdown
# Upgrade to v6
|
||
|
||
<p class="description">This guide explains why and how to upgrade from Material UI v5 to v6.</p>
|
||
|
||
## Why you should upgrade to Material UI v6
|
||
|
||
### React Server Component support
|
||
|
||
Material UI v6 introduces Pigment CSS, a zero-runtime CSS-in-JS styling engine to replace Emotion and styled-components as a more future-proof solution for writing styles in React 19 and beyond.
|
||
With Pigment CSS, styles are extracted at build time rather than runtime, avoiding client-side recalculations and unlocking React Server Component (RSC) compatibility.
|
||
This also leads to significant reductions in bundle sizes for Material UI apps.
|
||
|
||
**In v6, Pigment CSS is opt-in.**
|
||
Future major versions of Material UI will likely use Pigment CSS as the default styling solution.
|
||
Though optional, it's encouraged to try Pigment CSS out in your Material UI app.
|
||
If you wish to do so, refer to the guide for [migrating to Pigment CSS](/material-ui/migration/migrating-to-pigment-css/) once you're done upgrading to Material UI v6.
|
||
|
||
### Quality-of-life improvements
|
||
|
||
Material UI v6 features several other quality-of-life improvements, including:
|
||
|
||
- `ThemeProvider` now supports all of the `CssVarsProvider` features
|
||
- support for [container queries](/material-ui/customization/container-queries/)
|
||
- a [new theme utility](#color-mode-theme-utility) for adding styles to specific color modes
|
||
|
||
If you're using any of these packages, you can also change their version to `"6.0.0"`:
|
||
|
||
- `@mui/icons-material`
|
||
- `@mui/system`
|
||
- `@mui/lab`
|
||
- `@mui/material-nextjs`
|
||
- `@mui/styled-engine-sc`
|
||
- `@mui/utils`
|
||
|
||
Note that MUI X packages _do not_ follow the same versioning strategy as Material UI.
|
||
If you're using any of the following packages, they should remain unchanged during the upgrade process:
|
||
|
||
- `@mui/x-data-grid`
|
||
- `@mui/x-data-grid-pro`
|
||
- `@mui/x-data-grid-premium`
|
||
- `@mui/x-date-pickers`
|
||
- `@mui/x-date-pickers-pro`
|
||
- `@mui/x-charts`
|
||
- `@mui/x-tree-view`
|
||
- `@mui/x-tree-view-pro`
|
||
|
||
## Supported browsers and versions
|
||
|
||
The default bundle targets have changed in v6.
|
||
|
||
The exact versions will be pinned on release from the browserslist query: `"> 0.5%, last 2 versions, Firefox ESR, not dead, safari >= 15.4, iOS >= 15.4"`.
|
||
|
||
<!-- #stable-snapshot -->
|
||
|
||
- Node.js 14 (up from 12)
|
||
- Chrome 109 (up from 90)
|
||
- Edge 121 (up from 91)
|
||
- Firefox 115 (up from 78)
|
||
- Safari 15.4 in both macOS and iOS (up from 14 in macOS and 12.5 in iOS)
|
||
- and more (see [.browserslistrc `stable` entry](https://github.com/mui/material-ui/blob/v6.0.0/.browserslistrc#L11))
|
||
|
||
### Removed support for IE 11
|
||
|
||
Support for IE 11-the legacy bundle and all IE 11-related code-has been completely removed in v6.
|
||
This decreases Material UI's bundle size and eases future development.
|
||
|
||
If you need to support IE 11, you can use v5's [legacy bundle](https://v5.mui.com/material-ui/guides/minimizing-bundle-size/#legacy-bundle).
|
||
Note that it will not receive updates or bug fixes in the future.
|
||
|
||
### Minimum React version
|
||
|
||
The minimum supported version of React is v17.0.0 (the same as v5).
|
||
Use the snippet below to update your project (replace the `<version>` with the one you want):
|
||
|
||
<codeblock storageKey="package-manager">
|
||
|
||
```bash npm
|
||
npm install react@<version> react-dom@<version>
|
||
```
|
||
|
||
```bash pnpm
|
||
pnpm add react@<version> react-dom@<version>
|
||
```
|
||
|
||
```bash yarn
|
||
yarn add react@<version> react-dom@<version>
|
||
```
|
||
|
||
</codeblock>
|
||
|
||
### React 18 and below
|
||
|
||
If you are using React 18 or below, you need to set up a resolution of `react-is` package to the same version as the `react` you are using.
|
||
|
||
For example, if you are using `react@18.3.1`, do the following steps:
|
||
|
||
1. Install `react-is@18.3.1`.
|
||
|
||
<codeblock storageKey="package-manager">
|
||
|
||
```bash npm
|
||
npm install react-is@18.3.1
|
||
```
|
||
|
||
```bash pnpm
|
||
pnpm add react-is@18.3.1
|
||
```
|
||
|
||
```bash yarn
|
||
yarn add react-is@18.3.1
|
||
```
|
||
|
||
</codeblock>
|
||
|
||
2. Set the resolutions or overrides in the `package.json`.
|
||
|
||
<codeblock storageKey="package-manager">
|
||
|
||
```json npm
|
||
{
|
||
…
|
||
"overrides": {
|
||
"react-is": "^18.3.1"
|
||
}
|
||
}
|
||
```
|
||
|
||
```json pnpm
|
||
{
|
||
…
|
||
"overrides": {
|
||
"react-is": "^18.3.1"
|
||
}
|
||
}
|
||
```
|
||
|
||
```json yarn
|
||
{
|
||
…
|
||
"resolutions": {
|
||
"react-is": "^18.3.1"
|
||
}
|
||
}
|
||
```
|
||
|
||
</codeblock>
|
||
|
||
#### Why is this needed?
|
||
|
||
Material UI v6 uses `react-is@19`, which changed how React elements are identified.
|
||
|
||
If you're on React 18 or below, mismatched versions of `react-is` can cause runtime errors in prop type checks.
|
||
Forcing `react-is` to match your React version prevents these errors.
|
||
|
||
### Minimum TypeScript version
|
||
|
||
The minimum supported version of TypeScript has been increased from v3.5 to 4.7.
|
||
|
||
:::info
|
||
We align with types released by [DefinitelyTyped](https://github.com/DefinitelyTyped/DefinitelyTyped) (published on npm under the `@types` namespace).
|
||
|
||
We will not change the minimum supported version in a minor version of Material UI.
|
||
However, we recommend not using a TypeScript version older than the lowest supported version by DefinitelyTyped.
|
||
:::
|
||
|
||
If your project includes these packages, you'll need to update them:
|
||
|
||
- `@types/react`
|
||
- `@types/react-dom`
|
||
|
||
:::warning
|
||
Make sure that your application is still running without errors, and commit the changes before continuing to the next step.
|
||
:::
|
||
|
||
## Breaking changes
|
||
|
||
Material UI v6 was designed to introduce minimal breaking changes when upgrading from v5.
|
||
These include browser support updates, a Node.js version bump, and the removal of the UMD bundle.
|
||
These updates reduce the Material UI package size by 2.5MB—nearly 25% of the total size in v5.
|
||
|
||
Codemods are provided to handle the majority of these breaking changes.
|
||
|
||
:::info
|
||
This list is a work in progress.
|
||
Expect updates as new breaking changes are introduced.
|
||
:::
|
||
|
||
### UMD bundle removed
|
||
|
||
To align with React 19's removal of UMD builds, Material UI has also removed its UMD bundle.
|
||
This results in a reduction of the `@mui/material` package size by 2.5MB, or 25% of the total package size.
|
||
See [Package Phobia](https://packagephobia.com/result?p=@mui/material) for more details.
|
||
|
||
Instead, we recommend using ESM-based CDNs such as [esm.sh](https://esm.sh/).
|
||
For alternative installation methods, refer to the [CDN documentation](/material-ui/getting-started/installation/#cdn).
|
||
|
||
### Accordion
|
||
|
||
#### Summary wrapped in a heading
|
||
|
||
To meet the [W3C Accordion Pattern standard](https://www.w3.org/WAI/ARIA/apg/patterns/accordion/), the Accordion Summary is now wrapped with a default `<h3>` heading element.
|
||
This change may affect customizations relying on the previous DOM structure and CSS specificity.
|
||
Additionally, the default heading element might conflict with existing heading structures on your page.
|
||
|
||
If your styles or DOM manipulations depend on the old structure, you will need to update them to accommodate the new heading element.
|
||
If the default heading element conflicts with your existing structure, you can change the heading element using the `slotProps.heading.component` prop.
|
||
|
||
```jsx
|
||
<Accordion slotProps={{ heading: { component: 'h4' } }}>
|
||
<AccordionSummary
|
||
expandIcon={<ExpandMoreIcon />}
|
||
aria-controls="panel1-content"
|
||
id="panel1-header"
|
||
>
|
||
Accordion
|
||
</AccordionSummary>
|
||
<AccordionDetails>
|
||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada
|
||
lacus ex, sit amet blandit leo lobortis eget.
|
||
</AccordionDetails>
|
||
</Accordion>
|
||
```
|
||
|
||
#### Summary as a button (from v6.3.0)
|
||
|
||
- The Accordion Summary HTML structure has been updated to fix invalid HTML introduced by wrapping it with a heading shown above:
|
||
- The root element is now a `button`.
|
||
- Summary content and the icon wrapper are rendered as `span`.
|
||
- Developers using the previous `div` element for styling in the `AccordionSummary` should update their styling. Additionally, those using `Typography` for text, which defaults to rendering a `p` tag, should replace it with a `span`. You can use the `component` prop to replace the HTML tag (`<Typography component="span" />`), as shown in the [Accordion demos](https://mui.com/material-ui/react-accordion/).
|
||
|
||
### Autocomplete
|
||
|
||
Three new values have been introduced to the `reason` argument in the `onInputChange` callback of the Autocomplete component.
|
||
These values offer more granular options for three specific use cases previously covered by `"reset"`:
|
||
|
||
- `"blur"`: similar to `"reset"` but triggered when the focus moves away from the input. `clearOnBlur` must be `true`.
|
||
- `"selectOption"`: triggered when the input value changes after an option is selected.
|
||
- `"removeOption"`: triggered in multiple selection mode when a chip is removed as a result of its corresponding option being selected.
|
||
|
||
These are available in addition to the existing `"input"`, `"reset"`, and `"clear"` values.
|
||
|
||
### Chip
|
||
|
||
In earlier versions, the Chip component would lose focus when the user pressed the <kbd class="key">esc</kbd> key, which differs from how other button-like components work.
|
||
In v6, the Chip now retains focus as expected.
|
||
|
||
To preserve the previous behavior, add a custom `onKeyUp` handler as shown below:
|
||
|
||
```js
|
||
import * as React from 'react';
|
||
import Chip from '@mui/material/Chip';
|
||
|
||
export default function ChipExample() {
|
||
const chipRef = React.useRef(null);
|
||
const keyUpHandler = (event) => {
|
||
if (event.key === 'Escape' && chipRef.current) {
|
||
chipRef.current.blur();
|
||
}
|
||
};
|
||
return (
|
||
<Chip
|
||
label="Chip Outlined"
|
||
variant="outlined"
|
||
ref={chipRef}
|
||
onKeyUp={keyUpHandler}
|
||
/>
|
||
);
|
||
}
|
||
```
|
||
|
||
### Divider
|
||
|
||
When using vertical orientation, the Divider now renders a `<div>` with the corresponding accessibility attributes instead of `<hr>` to adhere to [the WAI-ARIA spec](https://www.w3.org/TR/wai-aria-1.2/#separator). You might need to adjust your styles accordingly if you are targeting `hr` tags in your CSS.
|
||
|
||
```diff
|
||
-import Divider from '@mui/material/Divider';
|
||
+import Divider, { dividerClasses } from '@mui/material/Divider';
|
||
|
||
const Main = styled.main({
|
||
- '& hr': {
|
||
+ [`& .${dividerClasses.root}`]: {
|
||
marginTop: '16px',
|
||
},
|
||
});
|
||
```
|
||
|
||
### Grid2
|
||
|
||
The `Grid2` (previously `Unstable_Grid2`) was updated and stabilized:
|
||
|
||
- The previous size (`xs`, `sm`, `md`, ...) and offset (`xsOffset`, `smOffset`, `mdOffset`, ...) props, which were named after the theme's breakpoints, were replaced with the `size` and `offset` props.
|
||
- The spacing mechanism was reworked to use the `gap` CSS property.
|
||
|
||
This brings some breaking changes described in the following sections.
|
||
|
||
#### Unstable prefix removed
|
||
|
||
The `Grid2` component API was stabilized, so its import no longer contains the `Unstable_` prefix:
|
||
|
||
```diff
|
||
-import { Unstable_Grid2 as Grid2 } from '@mui/material';
|
||
+import { Grid2 } from '@mui/material';
|
||
```
|
||
|
||
```diff
|
||
-import Grid from '@mui/material/Unstable_Grid2';
|
||
+import Grid from '@mui/material/Grid2';
|
||
```
|
||
|
||
#### Size and offset props renamed
|
||
|
||
In v5, the size and offset props were named to correspond with the theme's breakpoints.
|
||
For the default theme, these were:
|
||
|
||
- Size: `xs`, `sm`, `md`, `lg`, `xl`
|
||
- Offset: `xsOffset`, `smOffset`, `mdOffset`, `lgOffset`, `xlOffset`
|
||
|
||
In v6, these props are renamed to `size` and `offset`:
|
||
|
||
```diff
|
||
<Grid
|
||
- xs={12}
|
||
- sm={6}
|
||
- xsOffset={2}
|
||
- smOffset={3}
|
||
+ size={{ xs: 12, sm: 6 }}
|
||
+ offset={{ xs: 2, sm: 3 }}
|
||
>
|
||
```
|
||
|
||
If the size or offset is the same for all breakpoints, then you can use a single value:
|
||
|
||
```diff
|
||
-<Grid xs={6} xsOffset={2}>
|
||
+<Grid size={6} offset={2}>
|
||
```
|
||
|
||
Additionally, the `true` value for the `size` prop was renamed to `"grow"`:
|
||
|
||
```diff
|
||
-<Grid xs>
|
||
+<Grid size="grow">
|
||
```
|
||
|
||
Use this codemod to migrate your project to the new `size` and `offset` props:
|
||
|
||
```bash
|
||
npx @mui/codemod@latest v6.0.0/grid-v2-props <path/to/folder>
|
||
```
|
||
|
||
:::warning
|
||
You need to modify the import from `@mui/material/Unstable_Grid2` to `@mui/material/Grid2` before running the codemod.
|
||
:::
|
||
|
||
##### Using custom breakpoints
|
||
|
||
The usage described above also applies to custom breakpoints:
|
||
|
||
```diff
|
||
-<Grid mobile={12} mobileOffset={2} desktop={6} desktopOffset={4}>
|
||
+<Grid size={{ mobile: 12, desktop: 6 }} offset={{ mobile: 2, desktop: 4 }}>
|
||
```
|
||
|
||
You can use the same codemod for custom breakpoints by providing the breakpoints as an argument:
|
||
|
||
```bash
|
||
npx @mui/codemod@latest v6.0.0/grid-v2-props <path/to/folder> --jscodeshift='--muiBreakpoints=mobile,desktop'
|
||
```
|
||
|
||
#### disableEqualOverflow prop removed
|
||
|
||
In v5, the Grid overflowed its parent.
|
||
In v6, the Grid is correctly contained within its parent's padding:
|
||
|
||
<img src="/static/material-ui/migration-v5/grid-overflow-change.png" style="width: 814px;" alt="Before and after of the Grid no longer overflowing its parent in v6." width="1628" height="400" />
|
||
|
||
This eliminates the need for the `disableEqualOverflow` prop:
|
||
|
||
```diff
|
||
-<Grid disableEqualOverflow>
|
||
+<Grid>
|
||
```
|
||
|
||
#### Grid item spacing change
|
||
|
||
In v5, Grid items included spacing in their boxes.
|
||
In v6, Grid items no longer include spacing in their boxes by using the [CSS gap property](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/gap).
|
||
|
||
Note that the item position doesn't change.
|
||
|
||
<img src="/static/material-ui/migration-v5/grid-spacing-change.png" style="width: 814px;" alt="Before and after of the Grid items no longer including spacing in their boxes." width="1628" height="400" />
|
||
|
||
:::warning
|
||
These updates may lead to unexpected changes to your app's layout.
|
||
Still, we strongly recommend adopting this new behavior rather than trying to replicate the old pattern, as the new version is more predictable and modern.
|
||
:::
|
||
|
||
#### Container width
|
||
|
||
The updated Grid component doesn't grow to the full width of the container by default.
|
||
If you need the grid to grow to the full width, you can use the `sx` prop:
|
||
|
||
```diff
|
||
-<Grid container>
|
||
+<Grid container sx={{ width: '100%' }}>
|
||
|
||
// alternatively, if the Grid's parent is a flex container:
|
||
-<Grid container>
|
||
+<Grid container sx={{ flexGrow: 1 }}>
|
||
```
|
||
|
||
### ListItem
|
||
|
||
`ListItem`'s props `autoFocus`, `button`, `disabled`, and `selected`, deprecated in v5, have been removed. To replace the `button` prop, use `ListItemButton` instead. The other removed props are available in the `ListItemButton` component as well.
|
||
|
||
```diff
|
||
-<ListItem button />
|
||
+<ListItemButton />
|
||
```
|
||
|
||
Use this codemod to migrate your project to the `ListItemButton` component:
|
||
|
||
```bash
|
||
npx @mui/codemod@latest v6.0.0/list-item-button-prop <path/to/folder>
|
||
```
|
||
|
||
As the `ListItem` no longer supports these props, the class names related to these props were removed. You should use the `listItemButtonClasses` object instead.
|
||
|
||
```diff
|
||
-import { listItemClasses } from '@mui/material/ListItem';
|
||
+import { listItemButtonClasses } from '@mui/material/ListItemButton';
|
||
|
||
-listItemClasses.button
|
||
+listItemButtonClasses.root
|
||
|
||
-listItemClasses.focusVisible
|
||
+listItemButtonClasses.focusVisible
|
||
|
||
-listItemClasses.disabled
|
||
+listItemButtonClasses.disabled
|
||
|
||
-listItemClasses.selected
|
||
+listItemButtonClasses.selected
|
||
```
|
||
|
||
### Button with Loading State
|
||
|
||
As of `@mui/material` **v6.4.0**, the `LoadingButton` from Lab has been removed. Loading functionality is now part of the standard `Button` component. Update your import as follows:
|
||
|
||
```diff
|
||
-import { LoadingButton } from '@mui/lab';
|
||
+import { Button } from '@mui/material';
|
||
```
|
||
|
||
```diff
|
||
-import LoadingButton from '@mui/lab/LoadingButton';
|
||
+import Button from '@mui/material/Button';
|
||
```
|
||
|
||
For more details, see the [Loading section](/material-ui/react-button/#loading-2) in the [Material UI `Button` documentation](/material-ui/react-button/).
|
||
|
||
### Typography
|
||
|
||
The `color` prop in the `Typography` component is not a [system prop](https://mui.com/system/properties/) anymore. You can use the `sx` prop instead:
|
||
|
||
```diff
|
||
-<Typography color={(theme) => theme.palette.primary.main}>
|
||
+<Typography sx={{ color: (theme) => theme.palette.primary.main }}>
|
||
```
|
||
|
||
:::info
|
||
System props have been deprecated in favor of the `sx` prop. Check the [migration guide](/material-ui/migration/migrating-from-deprecated-apis/#system-props) for more information.
|
||
:::
|
||
|
||
You still can access some theme colors directly using the `color` prop. Check the [Typography component API page](/material-ui/api/typography/#typography-prop-color) for the whole list of colors.
|
||
|
||
```jsx
|
||
<Typography color="textSecondary">Secondary text</Typography>
|
||
```
|
||
|
||
### useMediaQuery types
|
||
|
||
The following deprecated types are removed in v6:
|
||
|
||
- `MuiMediaQueryList`: use `MediaQueryList` (from lib.dom.d.ts) instead.
|
||
- `MuiMediaQueryListEvent`: use `MediaQueryListEvent` (from lib.dom.d.ts) instead.
|
||
- `MuiMediaQueryListListener`: use `(event: MediaQueryListEvent) => void` instead.
|
||
|
||
## Breaking changes affecting testing
|
||
|
||
### Ripple effect
|
||
|
||
The ripple effect's performance has been improved in v6.
|
||
Because of this, you might need to update tests involving components with the ripple effect.
|
||
If you are using `fireEvent` from `@testing-library/react` to simulate user interactions, you will need to wrap these inside `act` and `await` to avoid React warnings:
|
||
|
||
```diff
|
||
- fireEvent.click(button);
|
||
+ await act(async () => fireEvent.mouseDown(button));
|
||
```
|
||
|
||
The components affected by this change are:
|
||
|
||
- All buttons
|
||
- Checkbox
|
||
- Chip
|
||
- Radio Group
|
||
- Switch
|
||
- Tabs
|
||
|
||
## Breaking changes affecting types
|
||
|
||
### Box
|
||
|
||
The `component` prop has been removed from the `BoxOwnProps` as it is already included in the `Box` type.
|
||
This might affect your code if you are using the `styled` function with the `Box` component.
|
||
If this is the case, use a `div` element instead of `Box`:
|
||
|
||
```diff
|
||
-const StyledBox = styled(Box)`
|
||
+const StyledDiv = styled('div')`
|
||
color: white;
|
||
`;
|
||
```
|
||
|
||
This yields the same end result.
|
||
If this doesn't work for you, you can also cast the `styled` returned value to `typeof Box`:
|
||
|
||
```diff
|
||
const StyledBox = styled(Box)`
|
||
color: white;
|
||
-`;
|
||
+` as typeof Box;
|
||
```
|
||
|
||
## Stabilized APIs
|
||
|
||
### CssVarsProvider and extendTheme
|
||
|
||
The `CssVarsProvider` and `extendTheme` APIs are now stable.
|
||
If you're already using them in v5 you can now drop the experimental prefix:
|
||
|
||
```diff
|
||
-import { experimental_extendTheme as extendTheme, Experimental_CssVarsProvider as CssVarsProvider } from '@mui/material/styles';
|
||
+import { extendTheme, CssVarsProvider } from '@mui/material/styles';
|
||
```
|
||
|
||
See [CSS theme variables](/material-ui/customization/css-theme-variables/overview/) for more details about working with these APIs.
|
||
|
||
### Color mode theme utility
|
||
|
||
Material UI v6 introduces a new utility for adding styles to specific color modes called `theme.applyStyles()`, designed to replace `theme.palette.mode` when applying light or dark styles:
|
||
|
||
```diff
|
||
const MyComponent = styled('button')(({ theme }) => ({
|
||
padding: '0.5rem 1rem',
|
||
border: '1px solid,
|
||
- borderColor: theme.palette.mode === 'dark' ? '#fff' : '#000',
|
||
+ borderColor: '#000',
|
||
+ ...theme.applyStyles('dark', {
|
||
+ borderColor: '#fff',
|
||
+ })
|
||
}))
|
||
```
|
||
|
||
Use these codemods to migrate your project to `theme.applyStyles()`:
|
||
|
||
```bash
|
||
npx @mui/codemod@latest v6.0.0/styled <path/to/folder-or-file>
|
||
npx @mui/codemod@latest v6.0.0/sx-prop <path/to/folder-or-file>
|
||
npx @mui/codemod@latest v6.0.0/theme-v6 <path/to/theme-file>
|
||
```
|
||
|
||
:::info
|
||
If you have a custom theme, run `v6.0.0/theme-v6` against the file that contains your custom `styleOverrides`.
|
||
Otherwise you can ignore this codemod.
|
||
:::
|
||
|
||
## Deprecations
|
||
|
||
It is not required to immediately go through the deprecations in order to use Material UI v6.
|
||
|
||
You can do it at your own pace by checking out the [deprecations page](/material-ui/migration/migrating-from-deprecated-apis/).
|
||
Those deprecations will be removed in the next major version.
|
||
|
||
## Pigment CSS integration (optional)
|
||
|
||
Once you've finished upgrading your app to v6, you'll be ready to start [migrating to Pigment CSS](/material-ui/migration/migrating-to-pigment-css/) for RSC support and a smaller bundle size.
|