# Mui X
> title: Date and Time Pickers - Accessibility
---
# Source: https://mui.com/x/react-data-grid/accessibility.md
# Source: https://mui.com/x/react-tree-view/accessibility.md
# Source: https://mui.com/x/react-date-pickers/accessibility.md
---
productId: x-date-pickers
title: Date and Time Pickers - Accessibility
githubLabel: 'scope: pickers'
packageName: '@mui/x-date-pickers'
---
# Accessibility
Learn how the Date and Time Pickers implement accessibility features and guidelines, including keyboard navigation that follows international standards.
## Guidelines
Common conformance guidelines for accessibility include:
- Globally accepted standard: [WCAG](https://www.w3.org/WAI/standards-guidelines/wcag/)
- US:
- [ADA](https://www.ada.gov/) - US Department of Justice
- [Section 508](https://www.section508.gov/) - US federal agencies
- Europe: [EAA](https://employment-social-affairs.ec.europa.eu/policies-and-activities/social-protection-social-inclusion/persons-disabilities/union-equality-strategy-rights-persons-disabilities-2021-2030/european-accessibility-act_en) (European Accessibility Act)
WCAG 2.1 has three levels of conformance: A, AA, and AAA.
Level AA exceeds the basic criteria for accessibility and is a common target for most organizations, so this is what we aim to support.
The WAI-ARIA Authoring Practices includes examples on [Date Picker Dialog](https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/examples/datepicker-dialog/) and [Date Picker Spin Button](https://www.w3.org/WAI/ARIA/apg/patterns/spinbutton/examples/datepicker-spinbuttons/) patterns, which provide valuable information on how to optimize the accessibility of these components.
### Dialog considerations
Both `Desktop` and `Mobile` Date and Time Pickers are using `role="dialog"` to display their interactive view parts and thus they should follow [Modal accessibility guidelines](/material-ui/react-modal/#accessibility).
This behavior is automated as much as possible, ensuring that the Date and Time Pickers are accessible in most cases.
A correct `aria-labelledby` value is assigned to the dialog component based on the following rules:
- Use `toolbar` ID if the toolbar is visible
- Use the ID of the input label if the toolbar is hidden
:::info
Make sure to provide an `aria-labelledby` prop to `popper` and/or `mobilePaper` slots in case you are using Date and Time Pickers component with **hidden toolbar** and **without a label**.
:::
## Screen reader compatibility
Date and Time Pickers use ARIA roles and robust focus management across the interactive elements to convey the necessary information to users, being optimized for use with assistive technologies.
## Keyboard support
The Date and Time Pickers consist of different associations of Field, Calendar, and Clock components.
Each of these components is designed to respond intuitively to keyboard interactions, providing extensive keyboard navigation support.
### Fields
The following table describes the keyboard support for all [field components](/x/react-date-pickers/fields/):
| Keys | Description |
| --------------------------------------------------------------------: | :---------------------------------------- |
| Arrow Left, Arrow Right | Moves focus among date/time sections |
| Arrow Up | Increases focused section value by 1 |
| Arrow Down | Decreases focused section value by 1 |
| Page Up | Increases focused section value by 5 |
| Page Down | Decreases focused section value by 5 |
| Home | Sets focused section to the minimal value |
| End | Sets focused section to the maximal value |
### Date Calendar
Among the [available view components](https://mui.com/x/react-date-pickers/date-calendar/#views), `day` is the only one that implements specific keyboard support:
| Keys | Description |
| -------------------------------: | :-------------------------------------------------------------- |
| Page Up | Moves calendar to next month, keeping focus on the same day |
| Page Down | Moves calendar to previous month, keeping focus on the same day |
| Home | Moves focus to the first day of the week |
| End | Moves focus to the last day of the week |
### Date Picker
The [Date Picker](/x/react-date-pickers/date-picker/) combines the functionalities of the Date Field and Date Calendar components.
Depending on which component is in focus, the Picker will provide the corresponding keyboard support, either from [Date Field](/x/react-date-pickers/accessibility/#fields) or [Date Calendar](/x/react-date-pickers/accessibility/#date-calendar).
### Date Range Calendar
The [Date Range Calendar](/x/react-date-pickers/date-range-calendar/) implements similar keyboard support as the day view of the [Date Calendar](/x/react-date-pickers/accessibility/#date-calendar) component, with a difference in the navigation between the previous and next months that must be achieved using the arrows in the calendar header.
| Keys | Description |
| --------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------- |
| Arrow Up, Arrow Down, Arrow Left, Arrow Right | Moves focus among the available values |
| Page Up | Moves focus to the last day of the month |
| Page Down | Moves focus to the first day of the month |
| Home | Moves focus to the first day of the week within the current month |
| End | Moves focus to the last day of the week within the current month |
### Date Range Picker
When interacting with the keyboard, the [Date Range Picker](/x/react-date-pickers/date-range-picker/) keeps the focus on the Field component, thereby offering the same keyboard navigation support as the [Date Range Field](/x/react-date-pickers/accessibility/#fields), having the changes consistently updated on the calendar component.
---
# Source: https://mui.com/x/react-date-pickers/adapters-locale.md
---
productId: x-date-pickers
title: Date and Time Pickers - Date format and localization
components: LocalizationProvider
githubLabel: 'scope: pickers'
packageName: '@mui/x-date-pickers'
---
# Date format and localization
Date and Time Pickers support formats from different locales.
## Getting started
The default locale of MUI X is English (United States). If you want to use other locales, follow the instructions below.
:::warning
This page focuses on date format localization.
If you need to translate text inside a component, check out the [Translated components](/x/react-date-pickers/localization/) page.
:::
## Set a custom locale
### With `dayjs`
For `dayjs`, import the locale and then pass its name to `LocalizationProvider`:
```tsx
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import 'dayjs/locale/de';
{children}
;
```
```tsx
import * as React from 'react';
import dayjs from 'dayjs';
import 'dayjs/locale/de';
import 'dayjs/locale/en-gb';
import 'dayjs/locale/zh-cn';
import Stack from '@mui/material/Stack';
import ToggleButton from '@mui/material/ToggleButton';
import ToggleButtonGroup from '@mui/material/ToggleButtonGroup';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import { DateField } from '@mui/x-date-pickers/DateField';
import { TimeField } from '@mui/x-date-pickers/TimeField';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
const locales = ['en', 'en-gb', 'zh-cn', 'de'];
type LocaleKey = (typeof locales)[number];
export default function LocalizationDayjs() {
const [locale, setLocale] = React.useState('en');
return (
{
if (newLocale != null) {
setLocale(newLocale);
}
}}
>
{locales.map((localeItem) => (
{localeItem}
))}
);
}
```
### With `date-fns`
For `date-fns`, import the locale and pass it to `LocalizationProvider`:
:::info
We support `date-fns` package v2.x, v3.x, and v4.x major versions.
A single adapter cannot work for all `date-fns` versions, because the way functions are exported has been changed in v3.x.
To use `date-fns` v2.x, you need to import the adapter from `@mui/x-date-pickers/AdapterDateFnsV2` instead of `@mui/x-date-pickers/AdapterDateFns`.
:::
```tsx
// with date-fns v3.x or v4.x
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
// with date-fns v2.x
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFnsV2';
// with date-fns v3.x or v4.x
import { de } from 'date-fns/locale/de';
// with date-fns v2.x
import de from 'date-fns/locale/de';
{children}
;
```
```tsx
import * as React from 'react';
import { de, enGB, zhCN } from 'date-fns/locale';
import Stack from '@mui/material/Stack';
import ToggleButton from '@mui/material/ToggleButton';
import ToggleButtonGroup from '@mui/material/ToggleButtonGroup';
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
import { DateField } from '@mui/x-date-pickers/DateField';
import { TimeField } from '@mui/x-date-pickers/TimeField';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
const locales = { 'en-us': undefined, 'en-gb': enGB, 'zh-cn': zhCN, de };
type LocaleKey = keyof typeof locales;
export default function LocalizationDateFns() {
const [locale, setLocale] = React.useState('en-us');
return (
{
if (newLocale != null) {
setLocale(newLocale);
}
}}
>
{Object.keys(locales).map((localeItem) => (
{localeItem}
))}
);
}
```
### With `luxon`
For `luxon`, pass the locale name to `LocalizationProvider`:
```tsx
import { AdapterLuxon } from '@mui/x-date-pickers/AdapterLuxon';
{children}
;
```
```tsx
import * as React from 'react';
import { DateTime } from 'luxon';
import Stack from '@mui/material/Stack';
import ToggleButton from '@mui/material/ToggleButton';
import ToggleButtonGroup from '@mui/material/ToggleButtonGroup';
import { AdapterLuxon } from '@mui/x-date-pickers/AdapterLuxon';
import { DateField } from '@mui/x-date-pickers/DateField';
import { TimeField } from '@mui/x-date-pickers/TimeField';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
const locales = ['en-us', 'en-gb', 'zh-cn', 'de'];
type LocaleKey = (typeof locales)[number];
export default function LocalizationLuxon() {
const [locale, setLocale] = React.useState('en-us');
return (
{
if (newLocale != null) {
setLocale(newLocale);
}
}}
>
{locales.map((localeItem) => (
{localeItem}
))}
);
}
```
:::warning
`AdapterLuxon` does not support `Settings.throwOnInvalid = true` [setting](https://moment.github.io/luxon/api-docs/index.html#settingsthrowoninvalid).
👍 Upvote [issue #11853](https://github.com/mui/mui-x/issues/11853) if you need support for it.
Don't hesitate to leave feedback on how you would like the data entry to behave.
:::
### With `moment`
For `moment`, import the locale and then pass its name to `LocalizationProvider`:
```tsx
import { AdapterMoment } from '@mui/x-date-pickers/AdapterMoment';
import 'moment/locale/de';
{children}
;
```
```tsx
import * as React from 'react';
import moment from 'moment';
import 'moment/locale/de';
import 'moment/locale/en-gb';
import 'moment/locale/zh-cn';
import Stack from '@mui/material/Stack';
import ToggleButton from '@mui/material/ToggleButton';
import ToggleButtonGroup from '@mui/material/ToggleButtonGroup';
import { AdapterMoment } from '@mui/x-date-pickers/AdapterMoment';
import { DateField } from '@mui/x-date-pickers/DateField';
import { TimeField } from '@mui/x-date-pickers/TimeField';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
const locales = ['en-us', 'en-gb', 'zh-cn', 'de'];
type LocaleKey = (typeof locales)[number];
export default function LocalizationMoment() {
const [locale, setLocale] = React.useState('en-us');
if (moment.locale() !== locale) {
moment.locale(locale);
}
return (
{
if (newLocale != null) {
setLocale(newLocale);
}
}}
>
{locales.map((localeItem) => (
{localeItem}
))}
);
}
```
## Meridiem — 12h/24h format
All the time and datetime components will automatically adjust to the locale's time setting, that is the 12-hour or 24-hour format.
You can override the default setting with the `ampm` prop:
```tsx
import * as React from 'react';
import dayjs from 'dayjs';
import 'dayjs/locale/de';
import 'dayjs/locale/en-gb';
import Stack from '@mui/material/Stack';
import ToggleButton from '@mui/material/ToggleButton';
import ToggleButtonGroup from '@mui/material/ToggleButtonGroup';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import { TimePicker } from '@mui/x-date-pickers/TimePicker';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
const locales = ['en', 'en-gb', 'de'];
type LocaleKey = (typeof locales)[number];
export default function AmPMCustomization() {
const [locale, setLocale] = React.useState('en');
return (
{
if (newLocale != null) {
setLocale(newLocale);
}
}}
>
{locales.map((localeItem) => (
{localeItem}
))}
);
}
```
## Custom formats
The format received by the props described below depends on the date library you are using.
Please refer to each library's documentation for the full format table:
- [Day.js](https://day.js.org/docs/display/format)
- [date-fns](https://date-fns.org/docs/format)
- [Luxon](https://moment.github.io/luxon/#/formatting?id=table-of-tokens)
- [Moment.js](https://momentjs.com/docs/#/displaying/format/)
### Custom field format
The fields have a default format that depends on the picker being used, the views enabled, and the 12h/24h format.
If this default format does not suit you, you can customize it using the `format` prop:
:::info
This prop is available on all fields and pickers.
:::
```tsx
import dayjs from 'dayjs';
import { DemoContainer } from '@mui/x-date-pickers/internals/demo';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { DateField } from '@mui/x-date-pickers/DateField';
import { DatePicker } from '@mui/x-date-pickers/DatePicker';
export default function CustomFieldFormat() {
return (
);
}
```
:::info
You can control the field format spacing using the [formatDensity](/x/react-date-pickers/custom-field/#change-the-format-density) prop.
:::
### Field-supported formats
Some formats might not yet be supported by the fields.
For example, they don't support day of the year or quarter.
Here is the list of the currently supported formats:
- The year
- ✅ 2-digits values (for example, `23`)
- ✅ 4-digits values (for example, `2023`)
- ❌ Values with ordinal (for example, `2023th`)
- The month
- ✅ 1-based digit (for example, `08`)
- ✅ Multi-letter values (for example, `Aug`, `August`)
- ❌ 1-letter values (for example, `A`) because several months are represented with the same letter
- The day of the month
- ✅ 1-based digit values (for example, `24`)
- ✅ 1-based digit values with ordinal (for example, `24th`)
- The day of the week
- ✅ 0-based digit values (for example, `03`)
- ✅ 1-based digit values (for example, `04`)
- ✅ Multi-letter values (for example, `Tue`, `Tuesday`)
- ❌ 1-letter values (for example, `T`) because several days of the week are represented with the same letter
- The hours
- ✅ 0-based 12-hours values (for example, `03`)
- ✅ 0-based 24-hours values (for example, `15`)
- ❌ 1-based values (for example, `24` instead of `00`)
- The minutes
- The seconds
- The meridiem
If you need to use some format that is not yet supported, please [open an issue](https://github.com/mui/mui-x/issues/new/choose) describing what is your exact use case.
Some new formats might be supported in the future, depending on the complexity of the implementation.
### Respect leading zeros in fields
By default, the value rendered in the field always contains digit zeros, even if your format says otherwise.
You can force the field to respect your format information by setting the `shouldRespectLeadingZeros` prop to `true`.
:::warning
When `shouldRespectLeadingZeros={true}`, the field will add an invisible character on the sections containing a single digit to make sure `onChange` is fired.
If you need to get the clean value from the input, you can remove this character using `input.value.replace(/\u200e/g, '')`.
:::
:::warning
Luxon is not able to respect the leading zeroes when using macro tokens (for example "DD"), so `shouldRespectLeadingZeros={true}` might lead to inconsistencies when using `AdapterLuxon`.
:::
```tsx
import dayjs from 'dayjs';
import { DemoContainer } from '@mui/x-date-pickers/internals/demo';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { DateField } from '@mui/x-date-pickers/DateField';
import { DatePicker } from '@mui/x-date-pickers/DatePicker';
export default function RespectLeadingZerosFieldFormat() {
return (
);
}
```
### Custom field placeholder
When a section is empty, the field displays its placeholder instead of an empty value.
For example, if you did not fill any value for the `year` section, the field will render the year placeholder.
These placeholders are based on your current component localization, not on your date localization.
```tsx
import 'dayjs/locale/de';
import { DemoContainer, DemoItem } from '@mui/x-date-pickers/internals/demo';
import { deDE } from '@mui/x-date-pickers/locales';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { DateField } from '@mui/x-date-pickers/DateField';
const germanLocale = deDE.components.MuiLocalizationProvider.defaultProps.localeText;
export default function FieldPlaceholder() {
return (
);
}
```
For more information on how to define your component localization, check out the [Translated components](/x/react-date-pickers/localization/) page.
:::warning
Placeholders translations depend on locale.
Some locales might keep using English placeholders, because that format is commonly used in a given locale.
:::
You can customize the specific placeholder section translation to your needs.
All the available placeholder translation methods and their parameters are available in [the source file](https://github.com/mui/mui-x/blob/HEAD/packages/x-date-pickers/src/locales/utils/pickersLocaleTextApi.ts).
You can override them using the `localeText` prop defined on the `LocalizationProvider` or on a specific Picker component if you need more fine-grained control.
A common use case is to change the placeholder of the month section to a short letter form (Jan, Feb, etc.).
The default translation implementation might not be what you want, so you can override it:
```tsx
params.contentType === 'digit' ? 'MM' : params.format,
}}
>
```
### Custom toolbar format
To customize the format used in the toolbar, use the `toolbarFormat` prop of the `toolbar` slot.
:::info
This prop is available on all pickers.
:::
```tsx
import dayjs from 'dayjs';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { StaticDatePicker } from '@mui/x-date-pickers/StaticDatePicker';
export default function CustomToolbarFormat() {
return (
);
}
```
### Custom day of week format
Use `dayOfWeekFormatter` to customize day names in the calendar header.
This prop takes two parameters, `day` (a string with the name of the day) and `date` (the day in the format of your date library), and returns the formatted string to display.
The default formatter only keeps the first letter of the name and capitalizes it.
:::warning
The first parameter `day` will be removed in v7 in favor of the second parameter `date` for more flexibility.
:::
:::info
This prop is available on all components that render a day calendar, including the Date Calendar as well as all Date Pickers, Date Time Pickers, and Date Range Pickers.
:::
The example below adds a dot at the end of each day in the calendar header:
```tsx
import * as React from 'react';
import dayjs, { Dayjs } from 'dayjs';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { DateCalendar } from '@mui/x-date-pickers/DateCalendar';
export default function CustomDayOfWeekFormat() {
const [value, setValue] = React.useState(dayjs('2022-04-17'));
return (
setValue(newValue)}
dayOfWeekFormatter={(weekday) => `${weekday.format('dd')}.`}
/>
);
}
```
### Custom calendar header format
To customize the format used on the calendar header, use the `format` prop of the `calendarHeader` slot.
:::info
This prop is available on all components that render a day calendar, including the Date Calendar as well as all Date Pickers, Date Time Pickers, and Date Range Pickers.
:::
```tsx
import dayjs from 'dayjs';
import { DemoContainer } from '@mui/x-date-pickers/internals/demo';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { DateCalendar } from '@mui/x-date-pickers/DateCalendar';
import { DateRangeCalendar } from '@mui/x-date-pickers-pro/DateRangeCalendar';
export default function CustomCalendarHeaderFormat() {
return (
);
}
```
## Custom start of week
The Date and Time Pickers are using the week settings provided by your date libraries.
Each adapter uses its locale to define the start of the week.
If the default start of the week defined in your adapter's locale is not the one you want, you can override it as shown in the following examples.
:::warning
If you want to update the start of the week after the first render of a component,
you will have to manually remount your component to apply the new locale configuration.
:::
### With `dayjs`
For `dayjs`, use the `updateLocale` plugin:
```ts
import updateLocale from 'dayjs/plugin/updateLocale';
dayjs.extend(updateLocale);
// Replace "en" with the name of the locale you want to update.
dayjs.updateLocale('en', {
// Sunday = 0, Monday = 1.
weekStart: 1,
});
```
### With `date-fns`
For `date-fns`, override the `options.weekStartsOn` of the used locale:
```ts
import { Locale } from 'date-fns';
// with date-fns v3.x or v4.x
import { enUS } from 'date-fns/locale/en-US';
// with date-fns v2.x
import enUS from 'date-fns/locale/en-US';
const customEnLocale: Locale = {
...enUS,
options: {
...enUS.options,
// Sunday = 0, Monday = 1.
weekStartsOn: 1,
},
};
```
### With `luxon`
For `luxon`, use the `Settings.defaultWeekSettings` object:
```ts
import { Settings, Info } from 'luxon';
Settings.defaultWeekSettings = {
// Sunday = 7, Monday = 1.
firstDay: 1,
// Makes sure we don't lose the other information from `defaultWeekSettings`
minimalDays: Info.getMinimumDaysInFirstWeek(),
weekend: Info.getWeekendWeekdays(),
};
```
:::warning
The [browser API](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/getWeekInfo) used by Luxon to determine the start of the week in the current locale is not yet supported by Firefox.
Users on this browser will always see Monday as the start of the week.
If you want to have the same start of week on all browsers,
you will have to manually override the `defaultWeekSettings` to set the `firstDay` corresponding to your locale.
For example, when using the `en-US` locale:
```ts
Settings.defaultWeekSettings = {
firstDay: 7,
minimalDays: Info.getMinimumDaysInFirstWeek(),
weekend: Info.getWeekendWeekdays(),
};
```
:::
### With `moment`
For `moment`, use the `moment.updateLocale` method:
```ts
import moment from 'moment';
// Replace "en" with the name of the locale you want to update.
moment.updateLocale('en', {
week: {
// Sunday = 0, Monday = 1.
dow: 1,
},
});
```
## RTL Support
Right-to-left languages such as Arabic, Persian, or Hebrew are supported.
Follow [this guide](/material-ui/customization/right-to-left/) to use them.
The example below demonstrates how to use an RTL language (Arabic) with some of the Date and Time Pickers components.
```tsx
import * as React from 'react';
import { prefixer } from 'stylis';
import rtlPlugin from '@mui/stylis-plugin-rtl';
import createCache from '@emotion/cache';
import { CacheProvider } from '@emotion/react';
import dayjs from 'dayjs';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { DateTimePicker } from '@mui/x-date-pickers/DateTimePicker';
import { createTheme, ThemeProvider, useTheme } from '@mui/material/styles';
// Create rtl cache
const cacheRtl = createCache({
key: 'pickers-rtl-demo',
stylisPlugins: [prefixer, rtlPlugin],
});
export default function PickersRTL() {
// Inherit the theme from the docs site (dark/light mode)
const existingTheme = useTheme();
const theme = React.useMemo(
() => createTheme(existingTheme, { direction: 'rtl' }),
[existingTheme],
);
return (
`, you can skip it.
slotProps={{
desktopPaper: {
dir: 'rtl',
},
mobilePaper: {
dir: 'rtl',
},
}}
/>
);
}
```
---
# Source: https://mui.com/x/react-data-grid/server-side-data/aggregation.md
# Source: https://mui.com/x/react-data-grid/aggregation.md
---
title: Data Grid - Aggregation
---
# Data Grid - Aggregation [](/x/introduction/licensing/#premium-plan 'Premium plan')
Add aggregation functions to the Data Grid to let users combine row values.
The Data Grid Premium provides tools to give end users the ability to aggregate and compare row values.
It includes [built-in functions](#built-in-functions) to cover common use cases such as sum, average, minimum, and maximum, as well as the means to [create custom functions](#creating-custom-functions) for all other needs.
End users can aggregate rows through the Data Grid interface by opening the column menu and selecting from the items under **Aggregation**.
The aggregated values are rendered in a footer row at the bottom of the Grid.
```tsx
import { DataGridPremium, GridColDef } from '@mui/x-data-grid-premium';
import { useMovieData } from '@mui/x-data-grid-generator';
const currencyFormatter = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
minimumFractionDigits: 0,
maximumFractionDigits: 0,
});
const COLUMNS: GridColDef[] = [
{ field: 'title', headerName: 'Title', width: 200, groupable: false },
{
field: 'gross',
headerName: 'Gross',
type: 'number',
width: 150,
groupable: false,
valueFormatter: (value) => {
if (!value) {
return value;
}
return currencyFormatter.format(value);
},
},
];
export default function AggregationInitialState() {
const data = useMovieData();
return (
);
}
```
:::info
This document covers client-side implementation.
For aggregation on the server side, see [Server-side aggregation](/x/react-data-grid/server-side-data/aggregation/).
:::
## Structure of the model
The aggregation model is an object.
The keys correspond to the columns, and the values are the names of the aggregation functions.
## Initializing aggregation
To initialize aggregation without controlling its state, provide the model to the `initialState` prop, as shown below:
```tsx
import { DataGridPremium, GridColDef } from '@mui/x-data-grid-premium';
import { useMovieData } from '@mui/x-data-grid-generator';
const currencyFormatter = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
minimumFractionDigits: 0,
maximumFractionDigits: 0,
});
const COLUMNS: GridColDef[] = [
{ field: 'title', headerName: 'Title', width: 200, groupable: false },
{
field: 'gross',
headerName: 'Gross',
type: 'number',
width: 150,
groupable: false,
valueFormatter: (value) => {
if (!value) {
return value;
}
return currencyFormatter.format(value);
},
},
];
export default function AggregationInitialState() {
const data = useMovieData();
return (
);
}
```
## Controlled aggregation
Use the `aggregationModel` prop to control aggregation passed to the Data Grid.
Use the `onAggregationModelChange` prop to listen to changes to aggregation and update the prop accordingly.
```tsx
import * as React from 'react';
import {
DataGridPremium,
GridAggregationModel,
GridColDef,
} from '@mui/x-data-grid-premium';
import { useMovieData } from '@mui/x-data-grid-generator';
const currencyFormatter = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
minimumFractionDigits: 0,
maximumFractionDigits: 0,
});
const COLUMNS: GridColDef[] = [
{ field: 'title', headerName: 'Title', width: 200, groupable: false },
{
field: 'gross',
headerName: 'Gross',
type: 'number',
width: 150,
groupable: false,
valueFormatter: (value) => {
if (!value) {
return value;
}
return currencyFormatter.format(value);
},
},
];
export default function AggregationControlled() {
const data = useMovieData();
const [aggregationModel, setAggregationModel] =
React.useState({
gross: 'sum',
});
return (
setAggregationModel(newModel)}
/>
);
}
```
## Disabling aggregation
### For all columns
To disable aggregation, set the `disableAggregation` prop to `true`.
This will disable all features related to aggregation, even if a model is provided.
```tsx
import { DataGridPremium } from '@mui/x-data-grid-premium';
import { useMovieData } from '@mui/x-data-grid-generator';
export default function AggregationDisabled() {
const data = useMovieData();
return (
);
}
```
### For specific columns
To disable aggregation on a specific column, set the `aggregable` property on its column definition (`GridColDef`) to `false`.
In the example below, the **Year** column is not aggregable since its `aggregable` property is set to `false`.
```tsx
import { DataGridPremium, GridColDef } from '@mui/x-data-grid-premium';
import { useMovieData } from '@mui/x-data-grid-generator';
const currencyFormatter = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
minimumFractionDigits: 0,
maximumFractionDigits: 0,
});
const COLUMNS: GridColDef[] = [
{
field: 'title',
headerName: 'Title',
width: 200,
groupable: false,
aggregable: false,
},
{
field: 'gross',
headerName: 'Gross',
type: 'number',
width: 150,
groupable: false,
valueFormatter: (value) => {
if (!value) {
return value;
}
return currencyFormatter.format(value);
},
},
{
field: 'year',
headerName: 'Year',
type: 'number',
aggregable: false,
},
];
export default function AggregationColDefAggregable() {
const data = useMovieData();
return (
);
}
```
## Aggregating non-aggregable columns
To apply aggregation programmatically on non-aggregable columns (columns with `aggregable: false` in the [column definition](/x/api/data-grid/grid-col-def/)), you can provide the aggregation model in one of the following ways:
- Pass `aggregation.model` to the `initialState` prop. This initializes aggregation with the provided model.
- Provide the `aggregationModel` prop. This controls aggregation with the provided model.
- Call the API method `setAggregationModel()`. This applies an aggregation with the provided model.
In the following demo, even though the **Year** column is not aggregable, it's still aggregated in read-only mode by providing an initial aggregation model as described above.
```tsx
import { DataGridPremium, GridColDef } from '@mui/x-data-grid-premium';
import { useMovieData } from '@mui/x-data-grid-generator';
const currencyFormatter = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
minimumFractionDigits: 0,
maximumFractionDigits: 0,
});
const COLUMNS: GridColDef[] = [
{
field: 'title',
headerName: 'Title',
width: 200,
groupable: false,
aggregable: false,
},
{
field: 'gross',
headerName: 'Gross',
type: 'number',
width: 150,
groupable: false,
valueFormatter: (value) => {
if (!value) {
return value;
}
return currencyFormatter.format(value);
},
},
{
field: 'year',
headerName: 'Year',
type: 'number',
aggregable: false,
},
];
export default function AggregationColDefNonAggregable() {
const data = useMovieData();
return (
);
}
```
## Usage with row grouping
When [row grouping](/x/react-data-grid/row-grouping/) is enabled, aggregated values can be displayed in the grouping rows as well as the top-level footer.
In the example below, the sum and the count of `true` values for each row group are aggregated and displayed in that group's row, while the total sum and count of `true` values for all rows are displayed in the footer.
```tsx
import {
DataGridPremium,
useGridApiRef,
useKeepGroupedColumnsHidden,
} from '@mui/x-data-grid-premium';
import { useDemoData } from '@mui/x-data-grid-generator';
export default function AggregationRowGrouping() {
const apiRef = useGridApiRef();
const { data } = useDemoData({
dataSet: 'Employee',
visibleFields: ['country', 'name', 'salary', 'isAdmin'],
rowLength: 10000,
});
console.log(data);
const initialState = useKeepGroupedColumnsHidden({
apiRef,
initialState: {
...data.initialState,
rowGrouping: {
model: ['country'],
},
aggregation: {
model: {
salary: 'sum',
isAdmin: 'sizeTrue',
},
},
},
});
return (
);
}
```
You can use the `getAggregationPosition` prop to customize this behavior.
This function takes the current group node as an argument (or `null` for the root group) and returns the position of the aggregated value.
The position can be one of three values:
- `"footer"`—the Data Grid adds a footer to the group to aggregate its rows.
- `"inline"`—the Data Grid disables aggregation on the grouping row.
- `null`—the Data Grid doesn't aggregate the group.
The following snippets build on the demo above to show various use cases for the `getAggregationPosition` prop:
```tsx
// Aggregate the root group in the top-level footer
// and the other groups in their grouping row
// (default behavior)
getAggregationPosition={(groupNode) => (groupNode.depth === -1 ? 'footer' : 'inline')}
// Aggregate all the groups in their grouping row;
// the root will not be aggregated
getAggregationPosition={(groupNode) => groupNode == null ? null : 'inline'}
// Only aggregate the company groups in the grouping row;
// director groups and root will not be aggregated
getAggregationPosition={(groupNode) => groupNode?.groupingField === 'company' ? 'inline' : null}
// Only aggregate the company group "Universal Pictures" in the grouping row
getAggregationPosition={(groupNode) =>
(groupNode?.groupingField === 'company' &&
groupNode?.groupingKey === 'Universal Pictures') ? 'inline' : null
}
// Only aggregate the root group in the top-level footer
getAggregationPosition={(groupNode) => groupNode == null ? 'footer' : null}
```
The demo below shows the sum aggregation in the footer of each group but not in the top-level footer:
```tsx
import {
DataGridPremium,
GridColDef,
useGridApiRef,
useKeepGroupedColumnsHidden,
} from '@mui/x-data-grid-premium';
import { useMovieData } from '@mui/x-data-grid-generator';
const currencyFormatter = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
minimumFractionDigits: 0,
maximumFractionDigits: 0,
});
const COLUMNS: GridColDef[] = [
{ field: 'title', headerName: 'Title', width: 200, groupable: false },
{
field: 'company',
headerName: 'Company',
width: 200,
},
{
field: 'director',
headerName: 'Director',
width: 200,
},
{
field: 'gross',
headerName: 'Gross',
type: 'number',
width: 150,
groupable: false,
valueFormatter: (value) => {
if (!value) {
return value;
}
return currencyFormatter.format(value);
},
},
];
export default function AggregationGetAggregationPosition() {
const data = useMovieData();
const apiRef = useGridApiRef();
const initialState = useKeepGroupedColumnsHidden({
apiRef,
initialState: {
rowGrouping: {
model: ['company', 'director'],
},
aggregation: {
model: {
gross: 'sum',
},
},
},
});
return (
groupNode.depth === -1 ? null : 'footer'
}
/>
);
}
```
## Usage with tree data
When working with [tree data](/x/react-data-grid/tree-data/), aggregated values can be displayed in the footer and in grouping rows.
:::info
If an aggregated value is displayed in a grouping row, it always takes precedence over any existing row data.
This means that even if the dataset explicitly provides group values, they will be ignored in favor of the aggregated values calculated by the Data Grid.
:::
In the demo below, the max values of the **Last modification** column and the sums of the **Size** column values are displayed in both the grouping rows and the footer:
```tsx
import {
DataGridPremium,
GridColDef,
GridRowsProp,
DataGridPremiumProps,
GridGroupingColDefOverride,
isAutogeneratedRow,
} from '@mui/x-data-grid-premium';
interface File {
hierarchy: string[];
size?: number;
updatedAt: string;
}
const rows: GridRowsProp = [
{
hierarchy: ['.gitignore'],
updatedAt: '2022-04-08T07:29:49.228Z',
},
{
hierarchy: ['README.md'],
size: 1671,
updatedAt: '2022-04-11T08:05:44.590Z',
},
{
hierarchy: ['next-env.d.ts'],
size: 201,
updatedAt: '2022-03-28T11:53:29.298Z',
},
{
hierarchy: ['next.config.js'],
size: 88,
updatedAt: '2022-03-28T11:53:29.298Z',
},
{
hierarchy: ['package.json'],
size: 766,
updatedAt: '2022-03-28T11:53:29.298Z',
},
{
hierarchy: ['pages', '_app.tsx'],
size: 1105,
updatedAt: '2022-03-28T11:53:29.298Z',
},
{
hierarchy: ['pages', '_document.tsx'],
size: 2715,
updatedAt: '2022-03-28T11:53:29.298Z',
},
{
hierarchy: ['pages', 'about.tsx'],
size: 1034,
updatedAt: '2022-03-28T11:53:29.298Z',
},
{
hierarchy: ['pages', 'index.tsx'],
size: 911,
updatedAt: '2022-03-28T11:53:29.298Z',
},
{
hierarchy: ['public', 'favicon.ico'],
size: 25931,
updatedAt: '2022-03-28T11:53:29.298Z',
},
{
hierarchy: ['src', 'Copyright.tsx'],
size: 428,
updatedAt: '2022-03-28T11:53:29.298Z',
},
{
hierarchy: ['src', 'Link.tsx'],
size: 2851,
updatedAt: '2022-04-08T07:29:49.228Z',
},
{
hierarchy: ['src', 'ProTip.tsx'],
size: 927,
updatedAt: '2022-03-28T11:53:29.298Z',
},
{
hierarchy: ['src', 'createEmotionCache.ts'],
size: 331,
updatedAt: '2022-03-28T11:53:29.298Z',
},
{
hierarchy: ['src', 'theme.ts'],
size: 332,
updatedAt: '2022-03-28T11:53:29.298Z',
},
{
hierarchy: ['tsconfig.json'],
size: 550,
updatedAt: '2022-03-28T11:53:29.298Z',
},
];
const columns: GridColDef[] = [
{
field: 'size',
headerName: 'Size',
type: 'number',
valueGetter: (value, row) => {
if (value == null) {
return isAutogeneratedRow(row) ? null : 0;
}
const sizeInKb = value / 1024;
// Round to 2 decimal places
return Math.round(sizeInKb * 100) / 100;
},
valueFormatter: (value) => `${Math.round(value * 100) / 100} Kb`,
},
{
field: 'updatedAt',
headerName: 'Last modification',
type: 'dateTime',
width: 200,
valueGetter: (value) => {
if (value == null) {
return null;
}
return new Date(value);
},
},
];
const getTreeDataPath: DataGridPremiumProps['getTreeDataPath'] = (row) =>
row.hierarchy;
const getRowId: DataGridPremiumProps['getRowId'] = (row) =>
row.hierarchy.join('/');
const groupingColDef: GridGroupingColDefOverride = {
headerName: 'Files',
width: 350,
};
export default function AggregationTreeData() {
return (
);
}
```
## Filtering
By default, aggregation only uses filtered rows.
To use all rows, set the `aggregationRowsScope` prop to `"all"`.
In the example below, the movie _Avatar_ doesn't pass the filters but is still used for the max aggregation of the **Gross** column:
```tsx
import { DataGridPremium, GridColDef } from '@mui/x-data-grid-premium';
import { useMovieData } from '@mui/x-data-grid-generator';
const currencyFormatter = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
minimumFractionDigits: 0,
maximumFractionDigits: 0,
});
const COLUMNS: GridColDef[] = [
{ field: 'title', headerName: 'Title', width: 200, groupable: false },
{
field: 'gross',
headerName: 'Gross',
type: 'number',
width: 150,
groupable: false,
valueFormatter: (value) => {
if (!value) {
return value;
}
return currencyFormatter.format(value);
},
},
];
export default function AggregationFiltering() {
const data = useMovieData();
return (
);
}
```
## Aggregation functions
### Basic structure
An aggregation function is an object that describes how to combine a given set of values.
```ts
const minAgg: GridAggregationFunction = {
// Aggregates the `values` into a single value.
apply: ({ values }) => Math.min(...values.filter((value) => value != null)),
// This aggregation function is only compatible with numerical values.
columnTypes: ['number'],
};
```
You can find full typing details in the [`GridAggregationFunction` API reference](/x/api/data-grid/grid-aggregation-function/).
### Built-in functions
The `@mui/x-data-grid-premium` package comes with a set of built-in aggregation functions to cover common use cases:
| Name | Behavior | Supported column types |
| :------------ | :--------------------------------------------------------- | :--------------------------- |
| `sum` | Returns the sum of all values in the group | `number` |
| `avg` | Returns the non-rounded average of all values in the group | `number` |
| `min` | Returns the smallest value of the group | `number`, `date`, `dateTime` |
| `max` | Returns the largest value of the group | `number`, `date`, `dateTime` |
| `size` | Returns the number of cells in the group | all |
| `size(true)` | Returns the number of cells with value `true` | `boolean` |
| `size(false)` | Returns the number of cells with value `false` | `boolean` |
### Removing a built-in function
#### From all columns
To remove specific aggregation functions from all columns, pass a filtered object to the `aggregationFunctions` prop.
In the example below, the sum function has been removed:
```tsx
import {
DataGridPremium,
GRID_AGGREGATION_FUNCTIONS,
GridColDef,
} from '@mui/x-data-grid-premium';
import { useMovieData } from '@mui/x-data-grid-generator';
const currencyFormatter = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
minimumFractionDigits: 0,
maximumFractionDigits: 0,
});
const COLUMNS: GridColDef[] = [
{ field: 'title', headerName: 'Title', width: 200, groupable: false },
{
field: 'gross',
headerName: 'Gross',
type: 'number',
width: 150,
groupable: false,
valueFormatter: (value) => {
if (!value) {
return value;
}
return currencyFormatter.format(value);
},
},
];
export default function AggregationRemoveFunctionAllColumns() {
const data = useMovieData();
return (
);
}
```
#### From a specific column
To limit the aggregation options in a given column, pass the `availableAggregationFunctions` property to the column definition.
This lets you specify which options are available to the end user:
```ts
const column = {
field: 'year',
type: 'number',
availableAggregationFunctions: ['max', 'min'],
};
```
In the example below, you can only aggregate the **Year** column using the max and min functions, whereas all functions are available for the **Gross** column:
```tsx
import { DataGridPremium, GridColDef } from '@mui/x-data-grid-premium';
import { useMovieData } from '@mui/x-data-grid-generator';
const currencyFormatter = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
minimumFractionDigits: 0,
maximumFractionDigits: 0,
});
const COLUMNS: GridColDef[] = [
{ field: 'title', headerName: 'Title', width: 200, groupable: false },
{
field: 'gross',
headerName: 'Gross',
type: 'number',
width: 150,
groupable: false,
valueFormatter: (value) => {
if (!value) {
return value;
}
return currencyFormatter.format(value);
},
},
{
field: 'year',
headerName: 'Year',
type: 'number',
availableAggregationFunctions: ['max', 'min'],
},
];
export default function AggregationRemoveFunctionOneColumn() {
const data = useMovieData();
return (
);
}
```
### Creating custom functions
An aggregation function is an object with the following shape:
```ts
const firstAlphabeticalAggregation: GridAggregationFunction =
{
// The `apply` method takes the values to aggregate and returns the aggregated value
apply: (params) => {
if (params.values.length === 0) {
return null;
}
const sortedValue = params.values.sort((a = '', b = '') => a.localeCompare(b));
return sortedValue[0];
},
// The `label` property defines the label displayed in the column header
// when this aggregation is being used.
label: 'firstAlphabetical',
// The `types` property defines which type of columns can use this aggregation function.
// Here, we only want to propose this aggregation function for `string` columns.
// If not defined, aggregation will be available for all column types.
columnTypes: ['string'],
};
```
To provide custom aggregation functions, pass them to the `aggregationFunctions` prop on the Data Grid Premium.
In the example below, the Grid has two custom functions for `string` columns: `firstAlphabetical` and `lastAlphabetical`:
```tsx
import {
DataGridPremium,
GRID_AGGREGATION_FUNCTIONS,
GridAggregationFunction,
GridColDef,
} from '@mui/x-data-grid-premium';
import { useMovieData } from '@mui/x-data-grid-generator';
const currencyFormatter = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
minimumFractionDigits: 0,
maximumFractionDigits: 0,
});
const COLUMNS: GridColDef[] = [
{
field: 'title',
headerName: 'Title',
width: 200,
groupable: false,
aggregable: false,
},
{
field: 'director',
headerName: 'Director',
width: 200,
},
{
field: 'gross',
headerName: 'Gross',
type: 'number',
width: 150,
groupable: false,
valueFormatter: (value) => {
if (!value) {
return value;
}
return currencyFormatter.format(value);
},
},
];
const firstAlphabeticalAggregation: GridAggregationFunction =
{
apply: (params) => {
if (params.values.length === 0) {
return null;
}
const sortedValue = params.values.sort((a = '', b = '') => a.localeCompare(b));
return sortedValue[0];
},
label: 'first alphabetical',
columnTypes: ['string'],
};
const lastAlphabeticalAggregation: GridAggregationFunction = {
apply: (params) => {
if (params.values.length === 0) {
return null;
}
const sortedValue = params.values.sort((a = '', b = '') => a.localeCompare(b));
return sortedValue[sortedValue.length - 1];
},
label: 'last alphabetical',
columnTypes: ['string'],
};
export default function AggregationCustomFunction() {
const data = useMovieData();
return (
);
}
```
### Aggregating data from multiple row fields
By default, the `apply` method of the aggregation function receives an array of values that represent a single field value from each row.
In the example below, the sum function receives the values of the `gross` field.
The values in the `profit` column are derived from the `gross` and `budget` fields of the row:
```tsx
{
field: 'profit',
type: 'number',
valueGetter: (value, row) => {
if (!row.gross || !row.budget) {
return null;
}
return (row.gross - row.budget) / row.budget;
}
}
```
To aggregate the `profit` column, you would have to calculate the sum of the `gross` and `budget` fields separately, and then use the formula from the example above to calculate the aggregated `profit` value.
To do this, you can use the `getCellValue()` callback on the aggregation function to transform the data being passed to the `apply()` method:
```tsx
const profit: GridAggregationFunction<{ gross: number; budget: number }, number> = {
label: 'profit',
getCellValue: ({ row }) => ({ budget: row.budget, gross: row.gross }),
apply: ({ values }) => {
let budget = 0;
let gross = 0;
values.forEach((value) => {
if (value) {
gross += value.gross;
budget += value.budget;
}
});
return (gross - budget) / budget;
},
columnTypes: ['number'],
};
```
```tsx
import {
DataGridPremium,
GridAggregationFunction,
GridColDef,
GRID_AGGREGATION_FUNCTIONS,
useGridApiRef,
useKeepGroupedColumnsHidden,
} from '@mui/x-data-grid-premium';
import { useMovieData, Movie } from '@mui/x-data-grid-generator';
const currencyFormatter = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
minimumFractionDigits: 0,
maximumFractionDigits: 0,
});
function calculateProfit(gross: number, budget: number) {
return (gross - budget) / budget;
}
const COLUMNS: GridColDef[] = [
{ field: 'title', headerName: 'Title', width: 200, groupable: false },
{
field: 'company',
headerName: 'Company',
width: 200,
},
{
field: 'profit',
headerName: 'Profit',
type: 'number',
width: 70,
groupable: false,
valueGetter: (value, row) => {
if (!row.gross || !row.budget) {
return null;
}
return calculateProfit(row.gross, row.budget);
},
valueFormatter: (value) => {
if (!value) {
return null;
}
return `${Math.round(value * 100)}%`;
},
},
{
field: 'gross',
headerName: 'Gross',
type: 'number',
minWidth: 140,
groupable: false,
valueFormatter: (value) => {
if (!value) {
return value;
}
return currencyFormatter.format(value);
},
},
{
field: 'budget',
headerName: 'Budget',
type: 'number',
minWidth: 140,
groupable: false,
valueFormatter: (value) => {
if (!value) {
return value;
}
return currencyFormatter.format(value);
},
},
];
const profit: GridAggregationFunction<{ gross: number; budget: number }, number> = {
label: 'profit',
getCellValue: ({ row }) => ({ budget: row.budget, gross: row.gross }),
apply: ({ values }) => {
let budget = 0;
let gross = 0;
values.forEach((value) => {
if (value) {
gross += value.gross;
budget += value.budget;
}
});
return calculateProfit(gross, budget);
},
columnTypes: ['number'],
};
export default function AggregationMultipleRowFields() {
const data = useMovieData();
const apiRef = useGridApiRef();
const initialState = useKeepGroupedColumnsHidden({
apiRef,
initialState: {
rowGrouping: {
model: ['company'],
},
aggregation: {
model: {
gross: 'sum',
budget: 'sum',
profit: 'profit',
},
},
},
});
return (
);
}
```
### Custom value formatter
By default, an aggregated cell uses the value formatter of its corresponding column.
But for some columns, the format of the aggregated value might differ from that of the column values.
You can provide a `valueFormatter()` method to the aggregation function to override the column's default formatting:
```ts
const aggregationFunction: GridAggregationFunction = {
apply: () => {
/* */
},
valueFormatter: (params) => {
/* format the aggregated value */
},
};
```
```tsx
import {
DataGridPremium,
GRID_AGGREGATION_FUNCTIONS,
GridAggregationFunction,
GridColDef,
} from '@mui/x-data-grid-premium';
import { useMovieData } from '@mui/x-data-grid-generator';
const currencyFormatter = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
minimumFractionDigits: 0,
maximumFractionDigits: 0,
});
const COLUMNS: GridColDef[] = [
{ field: 'title', headerName: 'Title', width: 200, groupable: false },
{
field: 'director',
headerName: 'Director',
width: 200,
},
{
field: 'gross',
headerName: 'Gross',
type: 'number',
width: 150,
groupable: false,
valueFormatter: (value) => {
if (!value) {
return value;
}
return currencyFormatter.format(value);
},
},
];
const firstAlphabeticalAggregation: GridAggregationFunction =
{
apply: (params) => {
if (params.values.length === 0) {
return null;
}
const sortedValue = params.values.sort((a = '', b = '') => a.localeCompare(b));
return sortedValue[0];
},
label: 'first alphabetical',
valueFormatter: (value) => `Agg: ${value}`,
columnTypes: ['string'],
};
export default function AggregationValueFormatter() {
const data = useMovieData();
return (
);
}
```
### Including pinned rows in the aggregation
By default, pinned rows are not included in the top-level aggregation calculation.
The demo below overrides the default aggregation functions to include values from the pinned rows in the top-level total aggreagation.
```tsx
import * as React from 'react';
import {
DataGridPremium,
GridColDef,
GRID_AGGREGATION_FUNCTIONS,
GridAggregationFunction,
isAutogeneratedRow,
gridColumnLookupSelector,
GridRowEntry,
GridInitialState,
GRID_ROOT_GROUP_ID,
} from '@mui/x-data-grid-premium';
import { useMovieData } from '@mui/x-data-grid-generator';
import { gridPinnedRowsSelector } from '@mui/x-data-grid/internals';
import { gridPivotActiveSelector } from '@mui/x-data-grid-pro/internals';
import FormControlLabel from '@mui/material/FormControlLabel';
import Checkbox from '@mui/material/Checkbox';
const currencyFormatter = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
minimumFractionDigits: 0,
maximumFractionDigits: 0,
});
const COLUMNS: GridColDef[] = [
{ field: 'title', headerName: 'Title', width: 200, groupable: false },
{ field: 'year', headerName: 'Year', width: 100, groupable: true },
{
field: 'gross',
headerName: 'Gross',
type: 'number',
width: 150,
groupable: false,
valueFormatter: (value) => {
if (!value) {
return value;
}
return currencyFormatter.format(value);
},
},
];
const getValuesFromRows = (
rows: GridRowEntry[],
aggregationFunction: GridAggregationFunction,
field: GridColDef['field'],
isPivotActive: boolean,
valueGetter: (row: any) => any,
) => {
const cellValues: any[] = [];
rows.forEach((rowEntry) => {
const row = rowEntry.model;
if (isAutogeneratedRow(row)) {
// Do not include the pinned aggregation row
return;
}
if (!row) {
return;
}
let value;
if (typeof aggregationFunction.getCellValue === 'function') {
value = aggregationFunction.getCellValue({ field, row });
} else if (isPivotActive) {
// Since we know that pivoted fields are flat, we can use the row directly, and save lots of processing time
value = row[field];
} else {
value = valueGetter(row);
}
if (typeof value !== 'undefined') {
cellValues.push(value);
}
});
return cellValues;
};
const aggregationFunctionsWithPinnedRows: Record =
{};
Object.keys(GRID_AGGREGATION_FUNCTIONS).forEach((name) => {
const aggFunc =
GRID_AGGREGATION_FUNCTIONS[name as keyof typeof GRID_AGGREGATION_FUNCTIONS];
const apply: GridAggregationFunction['apply'] = (params, api) => {
if (params.groupId !== GRID_ROOT_GROUP_ID) {
// Pinned rows can only impact top-level aggregation
return aggFunc.apply(params);
}
if (!api) {
return aggFunc.apply(params);
}
const apiRef = { current: api };
const pinnedRows = gridPinnedRowsSelector(apiRef);
if (pinnedRows.top.length === 0 && pinnedRows.bottom.length === 0) {
return aggFunc.apply(params);
}
let values = params.values;
const isPivotActive = gridPivotActiveSelector(apiRef);
const columnsLookup = gridColumnLookupSelector(apiRef);
const column = columnsLookup[params.field];
const valueGetter = (row: any) => apiRef.current.getRowValue(row, column);
if (pinnedRows.top) {
const topCellValues = getValuesFromRows(
pinnedRows.top,
aggFunc,
params.field,
isPivotActive,
valueGetter,
);
if (topCellValues.length > 0) {
values = topCellValues.concat(values);
}
}
if (pinnedRows.bottom) {
const bottomCellValues = getValuesFromRows(
pinnedRows.bottom,
aggFunc,
params.field,
isPivotActive,
valueGetter,
);
if (bottomCellValues.length > 0) {
values = values.concat(bottomCellValues);
}
}
return aggFunc.apply({ ...params, values });
};
aggregationFunctionsWithPinnedRows[name] = {
...aggFunc,
apply,
};
});
export default function AggregationPinnedRows() {
const data = useMovieData();
const [includePinnedRows, setIncludePinnedRows] = React.useState(true);
const initialState = React.useMemo(() => {
return {
aggregation: {
model: {
gross: 'sum',
},
},
};
}, []);
const { rows, topRows, bottomRows } = React.useMemo(() => {
const nonPinnedRows = [...data.rows];
return {
topRows: [nonPinnedRows.shift()],
rows: nonPinnedRows,
bottomRows: [nonPinnedRows.pop()],
};
}, [data.rows]);
return (
);
}
```
## Custom rendering
If the column used to display aggregation has a `renderCell()` property, then the aggregated cell calls it with a `params.aggregation` object to let you decide how you want to render it.
This object contains a `hasCellUnit` property to indicate whether the current aggregation has the same unit as the rest of the column's data—for instance, if the column is in `$`, is the aggregated value is also in `$`?
In the example below, all the aggregation functions are rendered with the rating UI aside from `size`, because it's not a valid rating:
```tsx
import * as React from 'react';
import { DataGridPremium, GridColDef } from '@mui/x-data-grid-premium';
import { useMovieData } from '@mui/x-data-grid-generator';
import Rating from '@mui/material/Rating';
const COLUMNS: GridColDef[] = [
{ field: 'title', headerName: 'Title', width: 200, groupable: false },
{
field: 'imdbRating',
headerName: 'Rating',
type: 'number',
width: 180,
availableAggregationFunctions: ['min', 'max', 'avg', 'size'],
display: 'flex',
// Imdb rating is on a scale from 0 to 10, the MUI rating component is on a scale from 0 to 5
renderCell: (params) => {
if (params.aggregation && !params.aggregation.hasCellUnit) {
return params.formattedValue;
}
return (
);
},
},
];
export default function AggregationRenderCell() {
const data = useMovieData();
// We take movies with the highest and lowest rating to have a visual difference
const rows = React.useMemo(() => {
return [...data.rows].sort((a, b) => b.imdbRating - a.imdbRating);
}, [data.rows]);
return (
);
}
```
## Selectors
{{"component": "modules/components/SelectorsDocs.js", "category": "Aggregation"}}
## API
- [DataGrid](/x/api/data-grid/data-grid/)
- [DataGridPro](/x/api/data-grid/data-grid-pro/)
- [DataGridPremium](/x/api/data-grid/data-grid-premium/)
- [GridAggregationFunction](/x/api/data-grid/grid-aggregation-function/)
---
# Source: https://mui.com/x/api/data-grid/ai-assistant-panel-trigger.md
# AiAssistantPanelTrigger API
## Demos
For examples and details on the usage of this React component, visit the component demo pages:
- Data Grid - AI Assistant Panel component 🚧
## Import
```jsx
import { AiAssistantPanelTrigger } from '@mui/x-data-grid-premium/components';
// or
import { AiAssistantPanelTrigger } from '@mui/x-data-grid-premium';
```
## Props
| Name | Type | Default | Required | Description |
|------|------|---------|----------|-------------|
| className | `func \| string` | - | No | |
| render | `element \| func` | - | No | |
> **Note**: The `ref` is forwarded to the root element (GridRoot).
## Source code
If you did not find the information on this page, consider having a look at the implementation of the component for more detail.
- [/packages/x-data-grid-premium/src/components/aiAssistantPanel/AiAssistantPanelTrigger.tsx](https://github.com/mui/material-ui/tree/HEAD/packages/x-data-grid-premium/src/components/aiAssistantPanel/AiAssistantPanelTrigger.tsx)
---
# Source: https://mui.com/x/react-data-grid/components/ai-assistant-panel.md
---
title: Data Grid - AI Assistant Panel component
productId: x-data-grid
components: AiAssistantPanelTrigger
packageName: '@mui/x-data-grid-premium'
githubLabel: 'scope: data grid'
---
# Data Grid - AI Assistant Panel component [](/x/introduction/licensing/#premium-plan 'Premium plan') 🚧
Customize the Data Grid's AI assistant panel.
:::warning
This component is incomplete.
Currently, the AI Assistant Panel Trigger is the only part of the AI Assistant Panel component available.
Future versions of the AI Assistant Panel component will make it possible to compose each of its parts for full customization.
:::
The AI assistant panel is part of the [AI Assistant feature](/x/react-data-grid/ai-assistant/).
You can use the AI Assistant Panel Trigger and [Toolbar](/x/react-data-grid/components/toolbar/) components when you need to customize the AI assistant panel trigger, or when implementing a custom toolbar.
## Basic usage
The demo below shows how to add an AI assistant panel trigger to a custom toolbar.
```tsx
import {
DataGridPremium,
Toolbar,
ToolbarButton,
AiAssistantPanelTrigger,
GridAiAssistantPanel,
} from '@mui/x-data-grid-premium';
import { mockPromptResolver, useDemoData } from '@mui/x-data-grid-generator';
import Tooltip from '@mui/material/Tooltip';
import AssistantIcon from '@mui/icons-material/Assistant';
function CustomToolbar() {
return (
}>
);
}
export default function GridAiAssistantPanelTrigger() {
const { data, loading } = useDemoData({
dataSet: 'Employee',
rowLength: 10,
maxColumns: 10,
});
return (
);
}
```
## Anatomy
```tsx
import { AiAssistantPanelTrigger } from '@mui/x-data-grid-premium';
;
```
### AI Assistant Panel Trigger
`` is a button that opens and closes the AI assistant panel.
It renders the `baseButton` slot.
## Custom elements
Use the `render` prop to replace default elements.
See [Components usage—Customization](/x/react-data-grid/components/usage/#customization) for more details.
## Accessibility
### ARIA
You must apply a text label or an `aria-label` attribute to the ``.
# AiAssistantPanelTrigger API
## Demos
For examples and details on the usage of this React component, visit the component demo pages:
- Data Grid - AI Assistant Panel component 🚧
## Import
```jsx
import { AiAssistantPanelTrigger } from '@mui/x-data-grid-premium/components';
// or
import { AiAssistantPanelTrigger } from '@mui/x-data-grid-premium';
```
## Props
| Name | Type | Default | Required | Description |
|------|------|---------|----------|-------------|
| className | `func \| string` | - | No | |
| render | `element \| func` | - | No | |
> **Note**: The `ref` is forwarded to the root element (GridRoot).
## Source code
If you did not find the information on this page, consider having a look at the implementation of the component for more detail.
- [/packages/x-data-grid-premium/src/components/aiAssistantPanel/AiAssistantPanelTrigger.tsx](https://github.com/mui/material-ui/tree/HEAD/packages/x-data-grid-premium/src/components/aiAssistantPanel/AiAssistantPanelTrigger.tsx)
---
# Source: https://mui.com/x/react-data-grid/ai-assistant.md
---
title: Ask Your Table - AI Assistant
---
# Ask Your Table - AI Assistant [](/x/introduction/licensing/#premium-plan 'Premium plan')
Translate natural language into Data Grid views.
:::warning
To use this feature you must have a prompt processing backend.
MUI [offers this service](/x/react-data-grid/ai-assistant/#with-muis-service) as a part of a premium package add-on.
Email us at [sales@mui.com](mailto:sales@mui.com) for more information.
:::
The AI Assistant feature lets users interact with the Data Grid component using natural language.
Type a prompt like "sort by name", "show amounts larger than 1000", or even make more complex queries like "which customers brought the most revenue the past year" in the prompt input field and the Data Grid will update accordingly.
In [supported browsers](https://developer.mozilla.org/en-US/docs/Web/API/SpeechRecognition#browser_compatibility), users can also prompt the assistant using their voice.
To enable this feature on the Data Grid, pass the `aiAssistant` prop and use the `GridAiAssistantPanel` component for `aiAssistantPanel` slot:
```tsx
import { DataGridPremium, GridAiAssistantPanel } from '@mui/x-data-grid-premium';
// ...
;
```
## Improving accuracy with example values
To increase the accuracy of the language processing, provide example values for the available columns via one of the methods below.
### Provide custom examples
Use the `examples` property on items of the `columns` array to provide custom examples as context for prompt processing.
The `examples` property should contain an array of possible values for each respective column.
:::info
AI Assistant demos use a limited version of [MUI's processing service](/x/react-data-grid/ai-assistant/#with-muis-service).
:::
```tsx
import * as React from 'react';
import {
DataGridPremium,
GridAiAssistantPanel,
unstable_gridDefaultPromptResolver as promptResolver,
} from '@mui/x-data-grid-premium';
import {
randomBoolean,
randomCompanyName,
randomCountry,
randomCreatedDate,
randomEmail,
randomInt,
randomJobTitle,
randomPhoneNumber,
randomTraderName,
useDemoData,
} from '@mui/x-data-grid-generator';
function createExamples(column: string) {
switch (column) {
case 'name':
return Array.from({ length: 5 }, () => randomTraderName());
case 'email':
return Array.from({ length: 5 }, () => randomEmail());
case 'position':
return Array.from({ length: 5 }, () => randomJobTitle());
case 'company':
return Array.from({ length: 5 }, () => randomCompanyName());
case 'salary':
return Array.from({ length: 5 }, () => randomInt(30000, 80000));
case 'phone':
return Array.from({ length: 5 }, () => randomPhoneNumber());
case 'country':
return Array.from({ length: 5 }, () => randomCountry());
case 'dateCreated':
return Array.from({ length: 5 }, () => randomCreatedDate());
case 'isAdmin':
return Array.from({ length: 5 }, () => randomBoolean());
default:
return [];
}
}
function processPrompt(prompt: string, context: string, conversationId?: string) {
return promptResolver(
'https://backend.mui.com/api/datagrid/prompt',
prompt,
context,
conversationId,
);
}
const VISIBLE_FIELDS = [
'id',
'avatar',
'name',
'website',
'rating',
'email',
'phone',
'username',
'position',
'company',
'salary',
'country',
'city',
'lastUpdated',
'dateCreated',
'isAdmin',
];
export default function AssistantWithExamples() {
const { data } = useDemoData({
dataSet: 'Employee',
visibleFields: VISIBLE_FIELDS,
rowLength: 1000,
});
const columns = React.useMemo(
() =>
data.columns.map((column) => ({
...column,
examples: createExamples(column.field),
})),
[data.columns],
);
return (
);
}
```
:::success
Provide examples for the [derived columns](/x/react-data-grid/pivoting/#derived-columns-in-pivot-mode) using the `getPivotDerivedColumns()` prop.
:::
### Use row data for examples
Pass the `allowAiAssistantDataSampling` prop to use row data to generate examples.
This is useful if you're dealing with non-sensitive data and want to skip creating custom examples for each column.
Data is collected randomly at the cell level, which means that the examples for a given column might not come from the same rows.
```tsx
import {
DataGridPremium,
GridAiAssistantPanel,
unstable_gridDefaultPromptResolver as promptResolver,
} from '@mui/x-data-grid-premium';
import { useDemoData } from '@mui/x-data-grid-generator';
const VISIBLE_FIELDS = [
'id',
'avatar',
'name',
'website',
'rating',
'email',
'phone',
'username',
'position',
'company',
'salary',
'country',
'city',
'lastUpdated',
'dateCreated',
'isAdmin',
];
function processPrompt(prompt: string, context: string, conversationId?: string) {
return promptResolver(
'https://backend.mui.com/api/datagrid/prompt',
prompt,
context,
conversationId,
);
}
export default function AssistantWithDataSampling() {
const { data } = useDemoData({
dataSet: 'Employee',
visibleFields: VISIBLE_FIELDS,
rowLength: 1000,
});
return (
);
}
```
### Data visualization
AI Assistant analyzes the query to determine if it is helpful to visualize the results.
[Integrate](/x/react-data-grid/charts-integration/) the Data Grid with [MUI X Charts](/x/react-charts/) to enable the Data Grid to apply the visualization instructions.
```tsx
import { useDemoData } from '@mui/x-data-grid-generator';
import {
DataGridPremium,
GridAiAssistantPanel,
unstable_gridDefaultPromptResolver as promptResolver,
GridChartsPanel,
GridChartsIntegrationContextProvider,
GridChartsRendererProxy,
useGridApiRef,
} from '@mui/x-data-grid-premium';
import {
ChartsRenderer,
configurationOptions,
ChartsRendererProps,
} from '@mui/x-charts-premium/ChartsRenderer';
function processPrompt(prompt: string, context: string, conversationId?: string) {
return promptResolver(
'https://backend.mui.com/api/datagrid/prompt',
prompt,
context,
conversationId,
);
}
export default function AssistantWithCharts() {
const { data } = useDemoData({
dataSet: 'Commodity',
rowLength: 10000,
});
const apiRef = useGridApiRef();
const initialState = {
...data.initialState,
pagination: {
...data.initialState?.pagination,
paginationModel: {
pageSize: 25,
},
},
chartsIntegration: {
charts: {
main: {
chartType: 'column',
},
},
},
};
return (
);
}
function CustomRenderer(props: ChartsRendererProps) {
// Do not render anything if the dimensions or values are empty
if (props.dimensions.length === 0 || props.values.length === 0) {
return null;
}
return ;
}
```
## Processing service integration
Natural language prompts must be processed by a service to understand what kinds of state changes must be applied to the Data Grid to match the user's request.
You can use MUI's processing service or build your own.
### With MUI's service
The Data Grid provides all the necessary elements for integration with MUI's service.
1. Contact [sales@mui.com](mailto:sales@mui.com) to get an API key for our processing service.
:::warning
Do not expose the API key to the public. Instead, keep it private, use a proxy server that receives prompt processing requests, adds the `x-api-key` header, and passes the request on to MUI's service.
This is an example of a [Fastify proxy](https://www.npmjs.com/package/@fastify/http-proxy) for the prompt requests.
```ts
fastify.register(proxy, {
upstream: 'https://backend.mui.com',
prefix: '/api/my-custom-path',
rewritePrefix: '/api/v1/datagrid/prompt',
replyOptions: {
rewriteRequestHeaders: (_, headers) => ({
...headers,
'x-api-key': process.env.MUI_DATAGRID_API_KEY,
}),
},
});
```
:::
2. Enable the AI Assistant feature by adding the `aiAssistant` prop.
This adds a new button to the Toolbar that controls the Assistant Panel's open state.
3. Provide `` as a component for the `aiAssistantPanel` slot.
Slot is by default `null` to prevent bundling of the panel and its child components in the projects that are not using the AI Assistant feature.
4. Provide the `onPrompt()` callback to pass the user's prompts to the service.
The service's response is used internally by the Data Grid to make the necessary state updates.
:::success
You can implement `onPrompt()` with `unstable_gridDefaultPromptResolver()`.
This adds the necessary headers and stringifies the body in the correct format for you.
It also makes it possible to provide additional context for better processing results, as shown below:
```ts
const PROMPT_RESOLVER_PROXY_BASE_URL =
process.env.NODE_ENV === 'development'
? 'http://localhost:3000'
: 'https://api.my-proxy.com';
function processPrompt(query: string, context: string, conversationId?: string) {
const additionalContext = `The rows represent: List of employees with their company, position and start date`;
return unstable_gridDefaultPromptResolver(
`${PROMPT_RESOLVER_PROXY_BASE_URL}/api/my-custom-path`,
query,
context,
conversationId,
{ additionalContext },
);
}
```
By default, MUI's prompt resolver service stores the queries made to the service to analyze potential errors and improve the service (data is never stored).
Enable `privateMode` to make the service only keep track of the data needed for billing, without any query related data.
```ts
function processPrompt(query: string, context: string, conversationId?: string) {
return unstable_gridDefaultPromptResolver(
`${PROMPT_RESOLVER_PROXY_BASE_URL}/api/my-custom-path`,
query,
context,
conversationId,
{ privateMode: true },
);
}
```
:::
5. Provide data examples in either of the following ways:
- Fill the `examples` prop in the `columns` array – this is recommended if you want to avoid exposing the row data to the AI Assistant.
- Provide access to the row data with `allowAiAssistantDataSampling` prop – since this uses real data, it may lead to better processing results.
6. Optionally, provide `referenceId` in the metadata to track spending and set limits for each entity sharing your API key.
The MUI Service supports `metadata` property through which you can send the reference that will be stored with the request.
Later, use that reference in the request history analysis.
::warning
The `metadata` object would store only `referenceId` property. If you are interested in storing more data, please [contact our support team](mailto:support@mui.com).
::
```ts
function processPrompt(query: string, context: string, conversationId?: string) {
return unstable_gridDefaultPromptResolver(
`${PROMPT_RESOLVER_PROXY_BASE_URL}/api/my-custom-path`,
query,
context,
conversationId,
{
metadata: {
referenceId: 'example-user-reference',
},
},
);
}
```
### With a custom service
The Data Grid exposes elements of the AI Assistant feature so you can build your own prompt processing service:
- The [`aiAssistant` API](/x/api/data-grid/grid-api/#grid-api-prop-aiAssistant) for processing the prompt results and updating state
- The `unstable_gridDefaultPromptResolver()` method for passing the prompt and context with the necessary headers to the processing service
Integrate these elements with your custom components and methods to suit your specific use case.
You can use a fully custom solution and apply the processing result using other Grid APIs such as [`setFilterModel()`](/x/api/data-grid/grid-api/#grid-api-prop-setFilterModel) or [`setSortModel()`](/x/api/data-grid/grid-api/#grid-api-prop-setSortModel) without the need to structure it as a `PromptResponse`.
To replace `unstable_gridDefaultPromptResolver()` with your own solution, send a POST request to MUI's API.
The body of the request requires `query` and `context` parameters.
`conversationId` and `options` are optional.
To keep the previous messages in the context you should pass the `conversationId` from the previous response.
The API response type is `Result`.
```ts
type Result = { ok: false; message: string } | { ok: true; data: T };
```
Your resolver should return `Promise`.
## API
- [DataGrid](/x/api/data-grid/data-grid/)
- [DataGridPro](/x/api/data-grid/data-grid-pro/)
- [DataGridPremium](/x/api/data-grid/data-grid-premium/)
---
# Source: https://mui.com/x/api/charts/animated-area.md
# AnimatedArea API
## Demos
For examples and details on the usage of this React component, visit the component demo pages:
- [Charts - Lines](/x/react-charts/lines/)
## Import
```jsx
import { AnimatedArea } from '@mui/x-charts/LineChart';
// or
import { AnimatedArea } from '@mui/x-charts';
// or
import { AnimatedArea } from '@mui/x-charts-pro';
// or
import { AnimatedArea } from '@mui/x-charts-premium';
```
## Props
| Name | Type | Default | Required | Description |
|------|------|---------|----------|-------------|
| skipAnimation | `bool` | `false` | No | |
> **Note**: The `ref` is forwarded to the root element.
## Source code
If you did not find the information on this page, consider having a look at the implementation of the component for more detail.
- [/packages/x-charts/src/LineChart/AnimatedArea.tsx](https://github.com/mui/material-ui/tree/HEAD/packages/x-charts/src/LineChart/AnimatedArea.tsx)
---
# Source: https://mui.com/x/api/charts/animated-line.md
# AnimatedLine API
## Demos
For examples and details on the usage of this React component, visit the component demo pages:
- [Charts - Lines](/x/react-charts/lines/)
## Import
```jsx
import { AnimatedLine } from '@mui/x-charts/LineChart';
// or
import { AnimatedLine } from '@mui/x-charts';
// or
import { AnimatedLine } from '@mui/x-charts-pro';
// or
import { AnimatedLine } from '@mui/x-charts-premium';
```
## Props
| Name | Type | Default | Required | Description |
|------|------|---------|----------|-------------|
| skipAnimation | `bool` | `false` | No | |
> **Note**: The `ref` is forwarded to the root element.
## Source code
If you did not find the information on this page, consider having a look at the implementation of the component for more detail.
- [/packages/x-charts/src/LineChart/AnimatedLine.tsx](https://github.com/mui/material-ui/tree/HEAD/packages/x-charts/src/LineChart/AnimatedLine.tsx)
---
# Source: https://mui.com/x/react-charts/animation.md
---
title: Charts - Animation
productId: x-charts
---
# Charts - Animation
Learn how to customize both CSS and JavaScript-based Chart animations.
Some elements of the MUI X Charts are animated by default.
For example, the bars in a Bar Chart rise from the axis, and the slices in a Pie Chart expand to fill the circle.
These animations are primarily built with CSS, but some use JavaScript-based React hooks as well.
You can use these hooks to animate other elements of the Charts that aren't animated by default, or to add animations to your own custom components.
To customize Chart animations, you may need to override CSS classes or implement the custom hooks provided, depending on your specific use case.
## Customizing CSS animations
You can override the default CSS classes to customize CSS-based animations.
The demo below shows how you can increase the label's animation duration to two seconds:
```tsx
import * as React from 'react';
import { pieArcLabelClasses, PieChart } from '@mui/x-charts/PieChart';
import Stack from '@mui/material/Stack';
import Button from '@mui/material/Button';
const data = [
{ id: 0, value: 10, label: 'series A' },
{ id: 1, value: 15, label: 'series B' },
{ id: 2, value: 20, label: 'series C' },
];
export default function CSSAnimationCustomization() {
const [key, rerender] = React.useReducer((x) => x + 1, 0);
return (
`${item.value}` }]}
width={200}
height={200}
hideLegend
sx={{
[`& .${pieArcLabelClasses.root}.${pieArcLabelClasses.animate}`]: {
animationDuration: '2s',
},
}}
/>
);
}
```
## Customizing JavaScript animations
To override JavaScript-based animations—or to use the Chart animations in custom components—you can use the custom animation hooks.
The Charts package provides the following animation hooks:
- `useAnimateArea()`
- `useAnimateBar()`
- `useAnimateBarLabel()`
- `useAnimateLine()`
- `useAnimatePieArc()`
- `useAnimatePieArcLabel()`
The demo below illustrates how to use these hooks by animating the bar labels to match the bar animation—click **Run Animation** to see it in action:
```tsx
import { BarChart, BarLabelProps } from '@mui/x-charts/BarChart';
import * as React from 'react';
import { useAnimateBarLabel } from '@mui/x-charts/hooks';
import Stack from '@mui/material/Stack';
import Button from '@mui/material/Button';
import { styled } from '@mui/material/styles';
export default function JSDefaultAnimation() {
const [key, animate] = React.useReducer((v) => v + 1, 0);
return (
);
}
const Text = styled('text')(({ theme }) => ({
...theme?.typography?.body2,
stroke: 'none',
fill: (theme.vars || theme)?.palette?.text?.primary,
}));
function AnimatedBarLabel(props: BarLabelProps) {
const {
seriesId,
dataIndex,
color,
isFaded,
isHighlighted,
classes,
xOrigin,
yOrigin,
x,
y,
width,
height,
layout,
skipAnimation,
...otherProps
} = props;
const animatedProps = useAnimateBarLabel({
xOrigin,
x,
yOrigin,
y,
width,
height,
layout,
skipAnimation,
});
return (
);
}
```
### The useAnimate() hook
For more fine-grained animation customization, you can use the `useAnimate(props, params)` hook.
This hook returns a ref as well as props to pass to the animated element.
Each time the `props` params are updated, the hook creates an interpolation from the previous value to the next one.
As each animation frame loads, it calls this interpolator to get the intermediate state and applies the result to the animated element.
(The attribute update is imperative to bypass the React lifecycle for improved performance.)
With `params` you can define the following properties:
- `skip`: If `true`, apply the new value immediately
- `ref`: A ref to merge with the ref returned from this hook
- `initialProps`: The props used to generate the animation of component creation; if none are provided, there is no initial animation
- `createInterpolator`: Create an interpolation function from the last to the next props
- `transformProps`: Optionally transform interpolated props to another format
- `applyProps`: Apply transformed props to the element
You can find more detailed explanations in the hook's JSDoc.
In the example below, labels are positioned above the bars they refer to and are animated with the `useAnimate()` hook:
```tsx
import { BarChart, BarLabelProps } from '@mui/x-charts/BarChart';
import * as React from 'react';
import { useAnimate } from '@mui/x-charts/hooks';
import Stack from '@mui/material/Stack';
import Button from '@mui/material/Button';
import { interpolateObject } from '@mui/x-charts-vendor/d3-interpolate';
export default function JSAnimationCustomization() {
const [key, animate] = React.useReducer((v) => v + 1, 0);
return (
);
}
function AnimatedBarLabel(props: BarLabelProps) {
const {
seriesId,
dataIndex,
color,
isFaded,
isHighlighted,
classes,
xOrigin,
yOrigin,
x,
y,
width,
height,
layout,
skipAnimation,
...otherProps
} = props;
const animatedProps = useAnimate(
{ x: x + width / 2, y: y - 2 },
{
initialProps: { x: x + width / 2, y: yOrigin },
createInterpolator: interpolateObject,
transformProps: (p) => p,
applyProps: (element: SVGTextElement, p) => {
element.setAttribute('x', p.x.toString());
element.setAttribute('y', p.y.toString());
},
skip: skipAnimation,
},
);
return (
);
}
```
## Third-party animation libraries
You can fully override the default Chart animations with your own (third-party) animation library.
:::warning
Third-party JavaScript animation libraries can cause performance issues, especially if you're rendering many data points or enabling interactions like zooming or highlighting.
It's essential to test the performance of your charts with your chosen animation library.
:::
### React Spring
The demo below shows how to integrate [React Spring](https://www.react-spring.dev/docs/getting-started) to add a bounce effect to the bar label animation:
```tsx
import { BarChart, BarLabelProps } from '@mui/x-charts/BarChart';
import * as React from 'react';
import { animated, useSpring } from '@react-spring/web';
import Stack from '@mui/material/Stack';
import Button from '@mui/material/Button';
export default function ReactSpringAnimationCustomization() {
const [key, animate] = React.useReducer((v) => v + 1, 0);
return (
);
}
function AnimatedBarLabel(props: BarLabelProps) {
const {
seriesId,
dataIndex,
color,
isFaded,
isHighlighted,
classes,
xOrigin,
yOrigin,
x,
y,
width,
height,
layout,
skipAnimation,
...otherProps
} = props;
const style = useSpring({
from: { y: yOrigin },
to: { y: y - 4 },
config: { tension: 100, friction: 10 },
});
return (
);
}
```
### Motion
The following demo uses the [Motion library](https://motion.dev/docs/react) for a fade-in effect on the points and lines in the chart:
```tsx
import {
LineChart,
type AnimatedLineProps,
type MarkElementProps,
} from '@mui/x-charts/LineChart';
import * as React from 'react';
import { motion } from 'motion/react';
import Stack from '@mui/material/Stack';
import Button from '@mui/material/Button';
export default function MotionAnimationCustomization() {
const [key, animate] = React.useReducer((v) => v + 1, 0);
return (
);
}
function AnimatedLine({ d, ownerState, skipAnimation }: AnimatedLineProps) {
return (
);
}
function AnimatedMark({ x, y, color, skipAnimation }: MarkElementProps) {
return (
);
}
```
---
# Source: https://mui.com/x/react-data-grid/api-object.md
# Data Grid - API object
Interact with the Data Grid using its API.
The API object is an interface containing the state and all the methods available to programmatically interact with the Data Grid.
You can find the list of all the API methods on the [`GridApi` page](/x/api/data-grid/grid-api/).
:::warning
New and experimental features are prefixed with `unstable_` and may be removed, renamed, or reworked at any time.
:::
## How to use the API object
The API object is accessible through the `apiRef` variable.
To access this variable, use `useGridApiContext` (inside `DataGrid`) or `useGridApiRef` (outside `DataGrid`).
### Inside the Data Grid
To access the API object inside component slots or inside renders (for instance, `renderCell` or `renderHeader`), use the `useGridApiContext` hook.
The snippet below renders `Button` inside the Grid's `GridToolbarContainer`:
```tsx
function CustomToolbar() {
const apiRef = useGridApiContext();
return (
);
}
```
:::info
You don't need to initialize the API object using `useGridApiRef` to be able to use it inside Data Grid components.
:::
```tsx
import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
import { DataGrid, GridToolbarContainer, useGridApiContext } from '@mui/x-data-grid';
import { useDemoData } from '@mui/x-data-grid-generator';
function CustomToolbar() {
const apiRef = useGridApiContext();
const handleGoToPage1 = () => apiRef.current.setPage(1);
return (
);
}
export default function UseGridApiContext() {
const { data, loading } = useDemoData({
dataSet: 'Commodity',
rowLength: 100,
maxColumns: 6,
});
return (
);
}
```
### Outside the Data Grid
When using the API object outside Data Grid components, you must initialize it using the `useGridApiRef` hook.
You can then pass it to the `apiRef` prop on the `DataGrid`:
```tsx
function CustomDataGrid(props) {
const apiRef = useGridApiRef();
return (
);
}
```
:::warning
The API object is populated by the `DataGrid`'s various plugins during the first render of the component.
If you try to use it in the first render of the component, it will crash because not all methods are registered yet.
:::
```tsx
import * as React from 'react';
import Button from '@mui/material/Button';
import Stack from '@mui/material/Stack';
import Box from '@mui/material/Box';
import { DataGrid, useGridApiRef } from '@mui/x-data-grid';
import { useDemoData } from '@mui/x-data-grid-generator';
export default function UseGridApiRef() {
const { data, loading } = useDemoData({
dataSet: 'Commodity',
rowLength: 100,
maxColumns: 6,
});
const [paginationModel, setPaginationModel] = React.useState({
page: 0,
pageSize: 10,
});
const apiRef = useGridApiRef();
const handleGoToPage1 = () => apiRef.current?.setPage(1);
return (
);
}
```
## Common use cases
### Access the disabled column features
You can control the disabled features of a column (for example hiding, sorting, filtering, pinning, grouping, etc) programmatically using `initialState`, controlled models, or the API object.
In the example below, the API object is used to build a custom sorting for the `firstName` column which is not sortable by the default grid UI (using the `colDef.sortable` property set to `false`).
```tsx
const columns = [{ field: 'rating', sortable: false }, ...otherColumns];
function CustomDataGrid(props) {
const apiRef = useGridApiRef();
return (
);
}
```
### Retrieve data from the state
See [State—Access the state](/x/react-data-grid/state/#access-the-state) for a detailed example.
### Listen to grid events
See [Events—Subscribing to events](/x/react-data-grid/events/#subscribing-to-events) for a detailed example.
## API
- [`GridApi`](/x/api/data-grid/grid-api/)
- [`DataGrid`](/x/api/data-grid/data-grid/)
- [`DataGridPro`](/x/api/data-grid/data-grid-pro/)
- [`DataGridPremium`](/x/api/data-grid/data-grid-premium/)
---
# Source: https://mui.com/x/api/charts/area-element.md
# AreaElement API
## Demos
For examples and details on the usage of this React component, visit the component demo pages:
- [Charts - Areas demos](/x/react-charts/areas-demo/)
- [Charts - Lines](/x/react-charts/lines/)
## Import
```jsx
import { AreaElement } from '@mui/x-charts/LineChart';
// or
import { AreaElement } from '@mui/x-charts';
// or
import { AreaElement } from '@mui/x-charts-pro';
// or
import { AreaElement } from '@mui/x-charts-premium';
```
## Props
| Name | Type | Default | Required | Description |
|------|------|---------|----------|-------------|
| skipAnimation | `bool` | `false` | No | |
| slotProps | `object` | `{}` | No | |
| slots | `object` | `{}` | No | |
> **Note**: The `ref` is forwarded to the root element.
## Slots
| Name | Default | Class | Description |
|------|---------|-------|-------------|
| area | `AnimatedArea` | - | The component that renders the area. |
## CSS
### Rule name
| Global class | Rule name | Description |
|--------------|-----------|-------------|
| - | faded | Styles applied to the root element when faded. |
| - | highlighted | Styles applied to the root element when highlighted. |
| - | root | Styles applied to the root element. |
| - | series | Styles applied to the root element for a specified series.
Needs to be suffixed with the series ID: `.${areaElementClasses.series}-${seriesId}`. |
## Source code
If you did not find the information on this page, consider having a look at the implementation of the component for more detail.
- [/packages/x-charts/src/LineChart/AreaElement.tsx](https://github.com/mui/material-ui/tree/HEAD/packages/x-charts/src/LineChart/AreaElement.tsx)
---
# Source: https://mui.com/x/api/charts/area-plot.md
# AreaPlot API
## Demos
For examples and details on the usage of this React component, visit the component demo pages:
- [Charts - Areas demos](/x/react-charts/areas-demo/)
- [Charts - Lines](/x/react-charts/lines/)
## Import
```jsx
import { AreaPlot } from '@mui/x-charts/LineChart';
// or
import { AreaPlot } from '@mui/x-charts';
// or
import { AreaPlot } from '@mui/x-charts-pro';
// or
import { AreaPlot } from '@mui/x-charts-premium';
```
## Props
| Name | Type | Default | Required | Description |
|------|------|---------|----------|-------------|
| onItemClick | `function(event: React.MouseEvent, lineItemIdentifier: LineItemIdentifier) => void` | - | No | |
| skipAnimation | `bool` | `false` | No | |
| slotProps | `object` | `{}` | No | |
| slots | `object` | `{}` | No | |
> **Note**: The `ref` is forwarded to the root element.
## Slots
| Name | Default | Class | Description |
|------|---------|-------|-------------|
| area | `AnimatedArea` | - | The component that renders the area. |
## Source code
If you did not find the information on this page, consider having a look at the implementation of the component for more detail.
- [/packages/x-charts/src/LineChart/AreaPlot.tsx](https://github.com/mui/material-ui/tree/HEAD/packages/x-charts/src/LineChart/AreaPlot.tsx)
---
# Source: https://mui.com/x/react-charts/areas-demo.md
---
title: Charts - Areas demos
productId: x-charts
components: LineChart, LineElement, LineHighlightElement, LineHighlightPlot, LinePlot, MarkElement, MarkPlot, AreaElement, AreaPlot
---
# Charts - Areas demos
This page groups demos using area charts.
## SimpleAreaChart
```tsx
import { LineChart, lineElementClasses } from '@mui/x-charts/LineChart';
import Box from '@mui/material/Box';
const margin = { right: 24 };
const uData = [4000, 3000, 2000, 2780, 1890, 2390, 3490];
const xLabels = [
'Page A',
'Page B',
'Page C',
'Page D',
'Page E',
'Page F',
'Page G',
];
export default function SimpleAreaChart() {
return (
);
}
```
## StackedAreaChart
```tsx
import { LineChart, lineElementClasses } from '@mui/x-charts/LineChart';
import Box from '@mui/material/Box';
const margin = { right: 24 };
const uData = [4000, 3000, 2000, 2780, 1890, 2390, 3490];
const pData = [2400, 1398, 9800, 3908, 4800, 3800, 4300];
const amtData = [2400, 2210, 0, 2000, 2181, 2500, 2100];
const xLabels = [
'Page A',
'Page B',
'Page C',
'Page D',
'Page E',
'Page F',
'Page G',
];
export default function StackedAreaChart() {
return (
);
}
```
## TinyAreaChart
```tsx
import { ChartContainer } from '@mui/x-charts/ChartContainer';
import { AreaPlot } from '@mui/x-charts/LineChart';
const uData = [4000, 3000, 2000, 2780, 1890, 2390, 3490];
const xLabels = [
'Page A',
'Page B',
'Page C',
'Page D',
'Page E',
'Page F',
'Page G',
];
export default function TinyAreaChart() {
return (
);
}
```
## PercentAreaChart
```tsx
import { LineChart } from '@mui/x-charts/LineChart';
import Box from '@mui/material/Box';
const time = [
new Date(2015, 1, 0),
new Date(2015, 2, 0),
new Date(2015, 3, 0),
new Date(2015, 4, 0),
new Date(2015, 5, 0),
new Date(2015, 6, 0),
new Date(2015, 7, 0),
];
const a = [4000, 3000, 2000, 2780, 1890, 2390, 3490];
const b = [2400, 1398, 9800, 3908, 4800, 3800, 4300];
const c = [2400, 2210, 2290, 2000, 2181, 2500, 2100];
const getPercents = (array: number[]) =>
array.map((v, index) => (100 * v) / (a[index] + b[index] + c[index]));
export default function PercentAreaChart() {
return (
);
}
```
## AreaChartConnectNulls
```tsx
import Stack from '@mui/material/Stack';
import { LineChart } from '@mui/x-charts/LineChart';
const data = [4000, 3000, 2000, null, 1890, 2390, 3490];
const xData = ['Page A', 'Page B', 'Page C', 'Page D', 'Page E', 'Page F', 'Page G'];
const margin = { right: 24 };
export default function AreaChartConnectNulls() {
return (
);
}
```
## AreaChartFillByValue
To display multiple colors in the area you can specify a gradient to fill the area (the same method can be applied on other SVG components).
You can pass this gradient definition as a children of the `` and use `sx` to override the area `fill` property.
To do so you will need to use the [``](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/linearGradient) and [``](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/stop) SVG elements.
The first part is to get the SVG total height.
Which can be done with the `useDrawingArea()` hook.
It's useful to define the `` as a vector that goes from the top to the bottom of our SVG container.
Then to define where the gradient should switch from one color to another, you can use the `useYScale` hook to get the y coordinate of value 0.
:::info
The `` offset is a ratio of gradient vector.
That's why you need to divide the coordinate by the SVG height.
:::
```tsx
import { ScaleLinear } from '@mui/x-charts-vendor/d3-scale';
import { green, red } from '@mui/material/colors';
import Stack from '@mui/material/Stack';
import { useYScale, useDrawingArea } from '@mui/x-charts/hooks';
import { LineChart, areaElementClasses } from '@mui/x-charts/LineChart';
const margin = { right: 24, bottom: 0 };
const data = [4000, 3000, -1000, 500, -2100, -250, 3490];
const xData = ['Page A', 'Page B', 'Page C', 'Page D', 'Page E', 'Page F', 'Page G'];
type ColorSwitchProps = {
threshold: number;
color1: string;
color2: string;
id: string;
};
function ColorSwitch({ threshold, color1, color2, id }: ColorSwitchProps) {
const { top, height, bottom } = useDrawingArea();
const svgHeight = top + bottom + height;
const scale = useYScale() as ScaleLinear; // You can provide the axis Id if you have multiple ones
const y0 = scale(threshold); // The coordinate of the origin
const off = y0 !== undefined ? y0 / svgHeight : 0;
return (
);
}
export default function AreaChartFillByValue() {
return (
);
}
function ColorPalette({ id }: { id: string }) {
const { top, height, bottom } = useDrawingArea();
const svgHeight = top + bottom + height;
const scale = useYScale() as ScaleLinear; // You can provide the axis Id if you have multiple ones
return (
);
}
```
---
# Source: https://mui.com/x/api/charts/axis-config.md
# AxisConfig API
## Import
```jsx
import { AxisConfig } from '@mui/x-charts-premium'
// or
import { AxisConfig } from '@mui/x-charts-pro'
// or
import { AxisConfig } from '@mui/x-charts'
```
## Props
| Name | Type | Default | Required | Description |
|------|------|---------|----------|-------------|
| id | `AxisId` | - | Yes | |
| scaleType | `'linear'` | - | Yes | |
| classes | `Partial` | - | No | |
| colorMap | `ContinuousColorConfig \| PiecewiseColorConfig` | - | No | |
| data | `readonly V[]` | - | No | |
| dataKey | `string` | - | No | |
| disableLine | `boolean` | `false` | No | |
| disableTicks | `boolean` | `false` | No | |
| domainLimit | `'nice' \| 'strict' \| ((min: number, max: number) => { min: number; max: number })` | - | No | |
| height | `number` | `45 if an axis label is provided, 25 otherwise.` | No | |
| hideTooltip | `boolean` | - | No | |
| ignoreTooltip | `boolean` | - | No | |
| label | `string` | - | No | |
| labelStyle | `ChartsTextProps['style']` | - | No | |
| offset | `number` | `0` | No | |
| position | `'top' \| 'bottom' \| 'none'` | - | No | |
| reverse | `boolean` | - | No | |
| slotProps | `Partial` | `{}` | No | |
| slots | `Partial` | `{}` | No | |
| sx | `SxProps` | - | No | |
| tickInterval | `'auto' \| ((value: any, index: number) => boolean) \| any[]` | `'auto'` | No | |
| tickLabelInterval | `'auto' \| ((value: any, index: number) => boolean)` | `'auto'` | No | |
| tickLabelPlacement | `'middle' \| 'tick'` | `'middle'` | No | |
| tickLabelStyle | `ChartsTextProps['style']` | - | No | |
| tickMaxStep | `number` | - | No | |
| tickMinStep | `number` | - | No | |
| tickNumber | `number` | - | No | |
| tickPlacement | `'start' \| 'end' \| 'middle' \| 'extremities'` | `'extremities'` | No | |
| tickSize | `number` | `6` | No | |
| tickSpacing | `number` | `0` | No | |
| valueFormatter | `(value: V, context: AxisValueFormatterContext) => string` | - | No | |
| zoom | `boolean \| ZoomOptions` | - | No | |
> **Note**: The `ref` is forwarded to the root element.
---
# Source: https://mui.com/x/react-charts/axis.md
---
title: Charts - Axis
productId: x-charts
components: ChartsAxis, ChartsReferenceLine, ChartsText, ChartsXAxis, ChartsYAxis, ChartsReferenceLine
---
# Charts - Axis
Define, format, and customize Chart axes.
An axis is a reference line that data points are measured against in a chart.
The MUI X Line Chart, Bar Chart, Scatter Chart, and Heatmap give you customization options for both x-axes and y-axes to suit a wide range of use cases.
## Creating custom axes
Use the `xAxis` and `yAxis` props to define custom axes.
These props expect an array of objects.
In the demo below, two lines are rendered using the same data points.
One has a linear y-axis and the other has a logarithmic one.
Each axis definition is identified by its property `id`.
Then each series specifies the axis it uses with the `xAxisId` and `yAxisId` properties.
```tsx
import Box from '@mui/material/Box';
import { LineChart } from '@mui/x-charts/LineChart';
const sample = [1, 10, 30, 50, 70, 90, 100];
export default function ScaleExample() {
return (
);
}
```
:::info
ID management, as shown in the example above, is not necessary for most common use cases.
If you don't provide `xAxisId` or `yAxisId` then the series uses the axis defined first.
This is why you won't see definitions of `id`, `xAxisId`, or `yAxisId` in most demos in the Charts docs—they rely on the default values.
:::
### Axis type and data
The axis type is specified by its property `scaleType`.
The axis definition object has a `data` property which expects an array of values corresponding to the `scaleType`, as shown in the table below:
| scaleType | Description | Number | Date | String |
| :------------------------------------- | :------------------------------------------------------- | :----: | :--: | :----: |
| `'band'` | Splits the axis in equal bands. | ✅ | ✅ | ✅ |
| `'point'` | Splits the axis in equally spaced points. | ✅ | ✅ | ✅ |
| `'linear'` `'log'` `'symlog'` `'sqrt'` | Maps numerical values to the available space. | ✅ | ❌ | ❌ |
| `'time'` `'utc'` | Maps JavaScript `Date()` objects to the available space. | ❌ | ✅ | ❌ |
Some series types also require specific axis attributes:
- In line charts, the `xAxis` must have a `data` array so each y-value maps to a specific x-value for proper chart rendering.
- In bar charts, the axis that represents categories (x-axis for vertical bars or y-axis for horizontal bars) must use `scaleType: 'band'`.
## Axis formatter
Axis data can be displayed in ticks, tooltips, and other locations.
You can use the `valueFormatter` property to change how the data is displayed.
The formatter's second argument provides rendering context for advanced use cases.
In the demo below, `valueFormatter` is used to shorten months and introduce a new line for ticks.
It uses the `context.location` to determine where the value is rendered.
```tsx
import { BarChart } from '@mui/x-charts/BarChart';
const otherSetting = {
height: 300,
yAxis: [{ label: 'rainfall (mm)', width: 60 }],
grid: { horizontal: true },
};
const dataset = [
{
london: 59,
paris: 57,
newYork: 86,
seoul: 21,
month: 'January',
},
{
london: 50,
paris: 52,
newYork: 78,
seoul: 28,
month: 'February',
},
{
london: 47,
paris: 53,
newYork: 106,
seoul: 41,
month: 'March',
},
{
london: 54,
paris: 56,
newYork: 92,
seoul: 73,
month: 'April',
},
{
london: 57,
paris: 69,
newYork: 92,
seoul: 99,
month: 'May',
},
{
london: 60,
paris: 63,
newYork: 103,
seoul: 144,
month: 'June',
},
{
london: 59,
paris: 60,
newYork: 105,
seoul: 319,
month: 'July',
},
{
london: 65,
paris: 60,
newYork: 106,
seoul: 249,
month: 'August',
},
{
london: 51,
paris: 51,
newYork: 95,
seoul: 131,
month: 'September',
},
{
london: 60,
paris: 65,
newYork: 97,
seoul: 55,
month: 'October',
},
{
london: 67,
paris: 64,
newYork: 76,
seoul: 48,
month: 'November',
},
{
london: 61,
paris: 70,
newYork: 103,
seoul: 25,
month: 'December',
},
];
const valueFormatter = (value: number | null) => `${value}mm`;
export default function FormatterDemo() {
return (
context.location === 'tick'
? `${month.slice(0, 3)} \n2023`
: `${month} 2023`,
height: 40,
},
]}
series={[{ dataKey: 'seoul', label: 'Seoul rainfall', valueFormatter }]}
{...otherSetting}
/>
);
}
```
### Ticks without labels
Some use cases may call for displaying ticks with no labels.
For example, it's common to use ticks to indicate a logarithmic scale but omit the labels from the axis when they'd be too numerous or complex to display.
The default tick formatter achieves this by rendering an empty string for ticks that should not show labels.
If you want to customize the formatting, but want to keep the default behavior for ticks without labels, you can check that the `context.defaultTickLabel` property is different from the empty string:
```tsx
import * as React from 'react';
import { ScatterChart } from '@mui/x-charts/ScatterChart';
import Stack from '@mui/material/Stack';
import Typography from '@mui/material/Typography';
import RadioGroup from '@mui/material/RadioGroup';
import FormControlLabel from '@mui/material/FormControlLabel';
import Radio from '@mui/material/Radio';
import FormControl from '@mui/material/FormControl';
import FormLabel from '@mui/material/FormLabel';
import { AxisValueFormatterContext, ScatterValueType } from '@mui/x-charts/models';
import { earthquakeData } from '../dataset/earthquakeData';
const settings = {
height: 400,
grid: { horizontal: true },
};
const data = Object.entries(earthquakeData).reduce(
(acc, [magnitude, events]) => {
acc.push({ x: Number.parseFloat(magnitude), y: events });
return acc;
},
[],
);
const formatter = new Intl.NumberFormat('en-US', {
notation: 'compact',
maximumFractionDigits: 1,
});
function valueFormatterIgnoreEmpty(value: any, context: AxisValueFormatterContext) {
if (context.location === 'tick' && context.defaultTickLabel === '') {
return '';
}
return formatter.format(value);
}
function valueFormatterShowAll(value: any) {
return formatter.format(value);
}
export default function TicksWithoutLabels() {
const [tickFormatter, setTickFormatter] = React.useState(
() => valueFormatterIgnoreEmpty,
);
return (
Worldwide Earthquake Count and Magnitude, 2020-2024
Source: US Geological SurveyTick Format
setTickFormatter(() =>
event.target.value === 'empty'
? valueFormatterIgnoreEmpty
: valueFormatterShowAll,
)
}
>
}
label="Ignore empty ticks"
/>
}
label="Show all values"
/>
);
}
```
### Using the D3 formatter
The context gives you access to the axis scale, the number of ticks (if applicable), and the default formatted value.
You can use the D3 [`tickFormat(tickNumber, specifier)`](https://d3js.org/d3-scale/linear#tickFormat) method to adapt the tick format based on the scale properties as shown below:
```tsx
import { ScaleLogarithmic } from '@mui/x-charts-vendor/d3-scale';
import { LineChart } from '@mui/x-charts/LineChart';
import { ChartsReferenceLine } from '@mui/x-charts/ChartsReferenceLine';
const otherSetting = {
height: 300,
grid: { horizontal: true, vertical: true },
};
// https://en.wikipedia.org/wiki/Low-pass_filter
const f0 = 440;
const frequencyResponse = (f: number) => 5 / Math.sqrt(1 + (f / f0) ** 2);
const dataset = [
0.1, 0.5, 0.8, 1, 5, 8, 10, 50, 80, 100, 500, 800, 1_000, 5_000, 8_000, 10_000,
50_000, 80_000, 100_000, 500_000, 800_000, 1_000_000,
].map((f) => ({ frequency: f, voltage: frequencyResponse(f) }));
export default function FormatterD3() {
return (
{
if (context.location === 'tick') {
const d3Text = (
context.scale as ScaleLogarithmic
).tickFormat(
context.tickNumber!,
'e',
)(f);
return d3Text;
}
return `${f.toLocaleString()}Hz`;
},
},
]}
yAxis={[
{
scaleType: 'log',
label: 'Vo/Vi',
width: 60,
valueFormatter: (f, context) => {
if (context.location === 'tick') {
const d3Text = (
context.scale as ScaleLogarithmic
).tickFormat(
30,
'f',
)(f);
return d3Text;
}
return f.toLocaleString();
},
},
]}
series={[{ dataKey: 'voltage' }]}
{...otherSetting}
>
);
}
```
## Axis subdomain
By default, the axis domain is computed so that all data is visible.
To show a specific range of values, you can provide the `min` and/or `max` properties to the axis definition:
```js
xAxis={[
{
min: 10,
max: 50,
},
]}
```
```tsx
import * as React from 'react';
import Slider from '@mui/material/Slider';
import Box from '@mui/material/Box';
import { ScatterChart } from '@mui/x-charts/ScatterChart';
import { Chance } from 'chance';
const chance = new Chance(42);
const data = Array.from({ length: 200 }, () => ({
x: chance.floating({ min: -25, max: 25 }),
y: chance.floating({ min: -25, max: 25 }),
})).map((d, index) => ({ ...d, id: index }));
const minDistance = 10;
export default function MinMaxExample() {
const [value, setValue] = React.useState([-25, 25]);
const handleChange = (
event: Event,
newValue: number | number[],
activeThumb: number,
) => {
if (!Array.isArray(newValue)) {
return;
}
if (newValue[1] - newValue[0] < minDistance) {
if (activeThumb === 0) {
const clamped = Math.min(newValue[0], 100 - minDistance);
setValue([clamped, clamped + minDistance]);
} else {
const clamped = Math.max(newValue[1], minDistance);
setValue([clamped - minDistance, clamped]);
}
} else {
setValue(newValue as number[]);
}
};
return (
);
}
```
### Relative axis subdomain
You can adjust the axis range relative to its data by using the `domainLimit` option.
This expects one of three possible values:
- `"nice"` (default): Rounds the domain to human-friendly values
- `"strict"`: Sets the domain to the min/max value to display
- `(minValue, maxValue) => { min, max }`: Receives the calculated extrema as parameters, and should return the axis domain
The demo below illustrates these differences in behavior, showing data ranging from -15 to 92 with different domain limits:
```tsx
import * as React from 'react';
import Box from '@mui/material/Box';
import { BarChart } from '@mui/x-charts/BarChart';
import TextField from '@mui/material/TextField';
import MenuItem from '@mui/material/MenuItem';
const settings = {
height: 220,
series: [{ data: [60, -15, 66, 68, 87, 82, 83, 85, 92, 75, 76, 50, 91] }],
margin: { top: 20, bottom: 10 },
} as const;
// Extend a value to match a multiple of the step.
function extend(value: number, step: number) {
if (value > 0) {
// If >0 go to the next step
return step * Math.ceil(value / step);
}
// If <0 go to the previous step
return step * Math.floor(value / step);
}
export default function CustomDomainYAxis() {
const [domainLimit, setDomainLimit] = React.useState<
'nice' | 'strict' | 'function'
>('nice');
return (
setDomainLimit(event.target.value as 'nice' | 'strict' | 'function')
}
label="domain limit"
sx={{ minWidth: 150, mb: 2 }}
>
({
min: extend(min, 10),
max: extend(max, 10),
})
: domainLimit,
},
]}
{...settings}
/>
);
}
```
## Axis direction
By default, the axes run from left to right and from bottom to top.
You can apply the `reverse` property to change this:
```tsx
import * as React from 'react';
import Box from '@mui/material/Box';
import Stack from '@mui/material/Stack';
import FormControlLabel from '@mui/material/FormControlLabel';
import Checkbox from '@mui/material/Checkbox';
import { ChartContainer } from '@mui/x-charts/ChartContainer';
import { LinePlot, MarkPlot } from '@mui/x-charts/LineChart';
import { BarPlot } from '@mui/x-charts/BarChart';
import { ChartsXAxis } from '@mui/x-charts/ChartsXAxis';
import { ChartsYAxis } from '@mui/x-charts/ChartsYAxis';
import { ChartsGrid } from '@mui/x-charts/ChartsGrid';
import { ChartsTooltip } from '@mui/x-charts/ChartsTooltip';
const dataset = [
{ min: -12, max: -4, precip: 79, month: 'Jan' },
{ min: -11, max: -3, precip: 66, month: 'Feb' },
{ min: -6, max: 2, precip: 76, month: 'Mar' },
{ min: 1, max: 9, precip: 106, month: 'Apr' },
{ min: 8, max: 17, precip: 105, month: 'Mai' },
{ min: 15, max: 24, precip: 114, month: 'Jun' },
{ min: 18, max: 26, precip: 106, month: 'Jul' },
{ min: 17, max: 26, precip: 105, month: 'Aug' },
{ min: 13, max: 21, precip: 100, month: 'Sept' },
{ min: 6, max: 13, precip: 116, month: 'Oct' },
{ min: 0, max: 6, precip: 93, month: 'Nov' },
{ min: -8, max: -1, precip: 93, month: 'Dec' },
];
const series = [
{ type: 'line', dataKey: 'min', color: '#577399' },
{ type: 'line', dataKey: 'max', color: '#fe5f55' },
{ type: 'bar', dataKey: 'precip', color: '#bfdbf7', yAxisId: 'rightAxis' },
] as const;
export default function ReverseExample() {
const [reverseX, setReverseX] = React.useState(false);
const [reverseLeft, setReverseLeft] = React.useState(false);
const [reverseRight, setReverseRight] = React.useState(false);
return (
setReverseX(event.target.checked)} />
}
label="reverse x-axis"
labelPlacement="end"
/>
setReverseLeft(event.target.checked)} />
}
label="reverse left axis"
labelPlacement="end"
/>
setReverseRight(event.target.checked)} />
}
label="reverse right axis"
labelPlacement="end"
/>
);
}
```
## Grid
You can add a grid in the background of a Cartesian chart with the `grid` prop.
This prop accepts an object with `vertical` and `horizontal` properties that are responsible for creating their respective lines when set to `true`.
If you use composition you can pass these as props to the `` component:
```jsx
```
```tsx
import { chartsGridClasses } from '@mui/x-charts/ChartsGrid';
import { BarChart } from '@mui/x-charts/BarChart';
import { dataset, valueFormatter } from '../dataset/weather';
const chartSetting = {
yAxis: [{ label: 'rainfall (mm)', width: 60 }],
height: 300,
};
export default function GridDemo() {
return (
);
}
```
## Tick position
### Automatic tick position
Use the `tickNumber` property to customize the number of ticks.
:::info
This number does _not_ necessarily represent the exact number of ticks displayed.
This is because D3 automatically places ticks to optimize for human readability, and it rounds up or down from the provided `tickNumber` as needed to accomplish this.
For example, if you set `tickNumber=5` but there are only four years to display on the axis, the component renders four total ticks (one for each year) instead of trying to divide four years into five.
:::
To better control how the ticks render, you can also provide `tickMinStep` and `tickMaxStep`, which compute `tickNumber` so that the step between two ticks respects the minimum and maximum values.
In the demo below, the top axis has a `tickMinStep` of half a day, and the bottom axis has a `tickMinStep` of a full day.
```tsx
import Box from '@mui/material/Box';
import { LineChart } from '@mui/x-charts/LineChart';
const timeData = [
new Date(2023, 7, 31),
new Date(2023, 7, 31, 12),
new Date(2023, 8, 1),
new Date(2023, 8, 1, 12),
new Date(2023, 8, 2),
new Date(2023, 8, 2, 12),
new Date(2023, 8, 3),
new Date(2023, 8, 3, 12),
new Date(2023, 8, 4),
];
const y1 = [5, 5, 10, 90, 85, 70, 30, 25, 25];
const y2 = [90, 85, 70, 25, 23, 40, 45, 40, 50];
const valueFormatter = (date: Date) =>
date.getHours() === 0
? date.toLocaleDateString('fr-FR', {
month: '2-digit',
day: '2-digit',
})
: date.toLocaleTimeString('fr-FR', {
hour: '2-digit',
});
const config = {
series: [{ data: y1 }, { data: y2 }],
height: 300,
};
const xAxisCommon = {
data: timeData,
scaleType: 'time',
valueFormatter,
} as const;
export default function TickNumber() {
return (
);
}
```
### Tick spacing
Use the `tickSpacing` property to define the minimum spacing in pixels between two ticks.
Having a minimum space between ticks improves the readability of the axis and can also improve the chart's performance.
This property defaults to 0 and is only available for ordinal axes, that is, axes with a band or point scale.
```tsx
import * as React from 'react';
import Stack from '@mui/material/Stack';
import Slider from '@mui/material/Slider';
import Typography from '@mui/material/Typography';
import { BarChartPro } from '@mui/x-charts-pro/BarChartPro';
import data from '../dataset/sp500-intraday.json';
const tickLabelDateFormatter = new Intl.DateTimeFormat(undefined, {
month: 'short',
day: 'numeric',
});
export default function TickSpacing() {
const [tickSpacing, setTickSpacing] = React.useState(50);
return (
Tick Spacing
setTickSpacing(value as number)}
valueLabelDisplay="auto"
min={0}
max={100}
step={5}
sx={{ mt: 2 }}
aria-labelledby="tickSpacing"
/>
new Date(Date.parse(d.date))),
valueFormatter: (v: Date) => tickLabelDateFormatter.format(v),
tickSpacing,
tickPlacement: 'middle',
zoom: true,
},
]}
series={[{ data: data.map((d) => d.close), label: 'Close' }]}
height={300}
/>
);
}
```
### Fixed tick position
If you want more control over the tick position, you can use the `tickInterval` property.
This property accepts an array of values that define exactly where ticks are placed.
For axes with the `'point'` scale type, the `tickInterval` property can be a filtering function of the type `(value, index) => boolean`.
In the demo below, both axes are set to `scaleType='point'`.
The top axis demonstrates the default behavior with a tick for each point.
The bottom axis uses a filtering function to only display a tick at the beginning of a day.
```tsx
import Box from '@mui/material/Box';
import { ShowMarkParams } from '@mui/x-charts/models';
import { LineChart } from '@mui/x-charts/LineChart';
export default function TickPosition() {
return (
time.getHours() === 0,
position: 'bottom',
},
{
...xAxisCommon,
scaleType: 'point',
position: 'top',
},
]}
{...config}
/>
);
}
const valueFormatter = (date: Date) =>
date.toLocaleDateString('fr-FR', {
month: '2-digit',
day: '2-digit',
});
const timeData = [
new Date(2023, 7, 31),
new Date(2023, 7, 31, 3),
new Date(2023, 7, 31, 6),
new Date(2023, 7, 31, 9),
new Date(2023, 7, 31, 12),
new Date(2023, 7, 31, 15),
new Date(2023, 7, 31, 18),
new Date(2023, 8, 1),
new Date(2023, 8, 1, 3),
new Date(2023, 8, 1, 6),
new Date(2023, 8, 1, 9),
new Date(2023, 8, 1, 12),
new Date(2023, 8, 1, 15),
new Date(2023, 8, 1, 18),
new Date(2023, 8, 2),
new Date(2023, 8, 2, 3),
new Date(2023, 8, 2, 6),
new Date(2023, 8, 2, 9),
new Date(2023, 8, 2, 12),
new Date(2023, 8, 2, 15),
new Date(2023, 8, 2, 18),
new Date(2023, 8, 3),
new Date(2023, 8, 3, 3),
new Date(2023, 8, 3, 6),
new Date(2023, 8, 3, 9),
new Date(2023, 8, 3, 12),
new Date(2023, 8, 3, 15),
new Date(2023, 8, 3, 18),
new Date(2023, 8, 4),
];
const y1 = [
5, 5.5, 5.3, 4.9, 5, 6.2, 8.9, 10, 15, 30, 80, 90, 94, 93, 85, 86, 75, 70, 68, 50,
20, 30, 35, 28, 25, 27, 30, 28, 25,
];
const y2 = [
90, 93, 89, 84, 85, 83, 73, 70, 63, 32, 30, 25, 18, 19, 23, 30, 32, 36, 40, 40, 42,
45, 46, 42, 39, 40, 41, 43, 50,
];
const showMark = (params: ShowMarkParams) => {
const { position } = params as ShowMarkParams;
return position.getHours() === 0;
};
const config = {
series: [
{ data: y1, showMark },
{ data: y2, showMark },
],
height: 300,
yAxis: [{ position: 'none' as const }],
};
const xAxisCommon = {
data: timeData,
scaleType: 'time',
valueFormatter,
} as const;
```
### Filtering tick labels
You can use the `tickLabelInterval` property to only display labels on a specific subset of ticks.
This is a filtering function in the `(value, index) => boolean` form.
For example, `tickLabelInterval: (value, index) => index % 2 === 0` will show the label every two ticks.
:::warning
The `value` and `index` arguments are those of the ticks, not the axis data.
:::
By default, ticks are filtered so that their labels don't overlap.
You can override this behavior with `tickLabelInterval: () => true` which forces the tick label to be shown for each tick.
In the example below, the top axis is a reference for the default behavior: tick labels don't overflow.
At the bottom, you can see one tick for the beginning and the middle of the day, but the tick label is only displayed for the beginning of the day.
```tsx
import Box from '@mui/material/Box';
import { ShowMarkParams } from '@mui/x-charts/models';
import { LineChart } from '@mui/x-charts/LineChart';
export default function TickLabelPosition() {
return (
[0, 12].includes(time.getHours()),
tickLabelInterval: (time) => time.getHours() === 0,
position: 'bottom',
},
{
...xAxisCommon,
id: 'topAxis',
scaleType: 'point',
position: 'top',
},
]}
yAxis={[{ position: 'none' }]}
{...config}
/>
);
}
const valueFormatter = (date: Date) =>
date.toLocaleDateString('fr-FR', {
month: '2-digit',
day: '2-digit',
});
const timeData = [
new Date(2023, 7, 31),
new Date(2023, 7, 31, 3),
new Date(2023, 7, 31, 6),
new Date(2023, 7, 31, 9),
new Date(2023, 7, 31, 12),
new Date(2023, 7, 31, 15),
new Date(2023, 7, 31, 18),
new Date(2023, 8, 1),
new Date(2023, 8, 1, 3),
new Date(2023, 8, 1, 6),
new Date(2023, 8, 1, 9),
new Date(2023, 8, 1, 12),
new Date(2023, 8, 1, 15),
new Date(2023, 8, 1, 18),
new Date(2023, 8, 2),
new Date(2023, 8, 2, 3),
new Date(2023, 8, 2, 6),
new Date(2023, 8, 2, 9),
new Date(2023, 8, 2, 12),
new Date(2023, 8, 2, 15),
new Date(2023, 8, 2, 18),
new Date(2023, 8, 3),
new Date(2023, 8, 3, 3),
new Date(2023, 8, 3, 6),
new Date(2023, 8, 3, 9),
new Date(2023, 8, 3, 12),
new Date(2023, 8, 3, 15),
new Date(2023, 8, 3, 18),
new Date(2023, 8, 4),
];
const y1 = [
5, 5.5, 5.3, 4.9, 5, 6.2, 8.9, 10, 15, 30, 80, 90, 94, 93, 85, 86, 75, 70, 68, 50,
20, 30, 35, 28, 25, 27, 30, 28, 25,
];
const y2 = [
90, 93, 89, 84, 85, 83, 73, 70, 63, 32, 30, 25, 18, 19, 23, 30, 32, 36, 40, 40, 42,
45, 46, 42, 39, 40, 41, 43, 50,
];
const showMark = (params: ShowMarkParams) => {
const { position } = params as ShowMarkParams;
return position.getHours() === 0;
};
const config = {
series: [
{ data: y1, showMark },
{ data: y2, showMark },
],
height: 300,
};
const xAxisCommon = {
data: timeData,
scaleType: 'time',
valueFormatter,
} as const;
```
### Ordinal tick management
Ordinal scales (`'band'` and `'point'`) display one tick per item by default.
If you have a date axis, you can use the `ordinalTimeTicks` property to configure which ticks to show.
It takes an array of frequencies at which ticks can be placed.
Those frequencies must be sorted from the largest to the smallest.
For example `['years', 'months', 'days']`.
Visible ticks are selected according to those frequencies and the `tickNumber`.
The `ordinalTimeTicks` property can either be an implementation of the `TickFrequencyDefinition` type or a subset of the built-in frequencies: `'years'`, `'quarterly'`, `'months'`, `'biweekly'`, `'weeks'`, `'days'`, `'hours'`.
When using `ordinalTimeTicks` the property `tickPlacement` is ignored, and computation are done as if set to `'middle'`.
In the following demo, you can modify the `ordinalTimeTicks` based on built-in frequencies and see how it impacts zoom behavior.
```tsx
import * as React from 'react';
import Box from '@mui/material/Box';
import { BarChartPro } from '@mui/x-charts-pro/BarChartPro';
import { BarSeriesType, XAxis, YAxis, ZoomOptions } from '@mui/x-charts-pro/models';
import { TickFrequency } from '@mui/x-charts/models';
import alphabetStock from '../dataset/GOOGL.json';
import SelectTimeFrequency from './SelectTimeFrequency';
const tickFrequencies: TickFrequency[] = [
'years',
'quarterly',
'months',
'biweekly',
'weeks',
'days',
];
export default function OrdinalTickPlacement() {
const [ordinalTimeTicks, setOrdinalTimeTicks] =
React.useState(defaultTicks);
const [tickNumber, setTickNumber] = React.useState(5);
return (
ordinalTimeTicks[frequency as keyof typeof ordinalTimeTicks],
),
},
]}
/>
);
}
type FilteredTicksState = Record;
const defaultTicks = Object.fromEntries(
tickFrequencies.map((frequency) => [frequency, true]),
) as FilteredTicksState;
const zoom: ZoomOptions = { minSpan: 1, filterMode: 'discard' };
const xAxis: XAxis = {
id: 'date',
data: alphabetStock.map((day) => new Date(day.date)),
scaleType: 'band',
zoom,
valueFormatter: (value) => value.toLocaleDateString(),
height: 30,
};
const barSettings = {
height: 200,
hideLegend: true,
margin: { bottom: 5 },
series: [
{
type: 'bar',
yAxisId: 'volume',
label: 'Volume',
color: 'lightgray',
data: alphabetStock.map((day) => day.volume),
} as BarSeriesType,
],
yAxis: [
{
id: 'volume',
scaleType: 'linear',
position: 'left',
valueFormatter: (value) => `${(value / 1000000).toLocaleString()}M`,
width: 55,
} as YAxis,
],
};
```
The `TickFrequencyDefinition` is an object made of following properties:
- `getTickNumber: (from: Date, to: Date) => number` Returns the number of ticks that will be displayed between `from` and `to` dates.
- `isTick: (prev: Date, value: Date) => boolean` Returns `true` is a tick should be placed on `value`. For example if it's the beginning of a new month.
- `format: (d: Date) => string` Returns for tick label.
The built-in frequency definitions are exported as `tickFrequencies` from `'@mui/x-charts/utils'`.
In the following demo, we use the `tickFrequencies` to display quarters and weeks with different labels.
```tsx
import * as React from 'react';
import Box from '@mui/material/Box';
import { BarChartPro } from '@mui/x-charts-pro/BarChartPro';
import { BarSeriesType, XAxis, YAxis, ZoomOptions } from '@mui/x-charts-pro/models';
import { tickFrequencies } from '@mui/x-charts/utils';
import alphabetStock from '../dataset/GOOGL.json';
export default function CustomTickFrequency() {
return (
);
}
const quarterFormat = (d: Date) => `Q${Math.floor(d.getMonth() / 3) + 1}`;
const weekFormat = (d: Date) => `W${getWeekNumber(d)}`;
const zoom: ZoomOptions = { minSpan: 1, filterMode: 'discard' };
const xAxis: XAxis = {
id: 'date',
data: alphabetStock.map((day) => new Date(day.date)),
scaleType: 'band',
zoom,
valueFormatter: (value) => value.toLocaleDateString(),
height: 30,
tickNumber: 15,
};
const barSettings = {
height: 200,
hideLegend: true,
margin: { bottom: 5 },
series: [
{
type: 'bar',
yAxisId: 'volume',
label: 'Volume',
color: 'lightgray',
data: alphabetStock.map((day) => day.volume),
} as BarSeriesType,
],
yAxis: [
{
id: 'volume',
scaleType: 'linear',
position: 'left',
valueFormatter: (value) => `${(value / 1000000).toLocaleString()}M`,
width: 55,
} as YAxis,
],
grid: { vertical: true, horizontal: true },
};
function getWeekNumber(date: Date) {
const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
const dayNum = d.getUTCDay() || 7;
d.setUTCDate(d.getUTCDate() + 4 - dayNum);
const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
return Math.ceil(((d.getTime() - yearStart.getTime()) / 86400000 + 1) / 7);
}
```
## Position
You can customize axis positioning with the `position` property of the axis configuration.
This property expects the following values:
- `'top'` or `'bottom'` for the x-axis
- `'left'` or `'right'` for the y-axis
- `'none'` to hide the axis
```tsx
import Box from '@mui/material/Box';
import { ScatterChart } from '@mui/x-charts/ScatterChart';
import { Chance } from 'chance';
const chance = new Chance(42);
const data = Array.from({ length: 200 }, () => ({
x: chance.floating({ min: -25, max: 25 }),
y: chance.floating({ min: -25, max: 25 }),
})).map((d, index) => ({ ...d, id: index }));
const params = {
series: [{ data }],
height: 300,
margin: { top: 12, right: 12, bottom: 20, left: 12 },
};
export default function ModifyAxisPosition() {
return (
);
}
```
### Hiding axes
To hide an axis, set its `position` to `'none'`.
Note that the axis is still computed and used for scaling.
```tsx
import { BarChart } from '@mui/x-charts/BarChart';
export default function HidingAxis() {
return (
);
}
```
### Multiple axes on one side
You can display multiple axes on one side.
If two or more axes share the same `position`, they're displayed in the order they're defined from closest to farthest away from the chart.
```tsx
import Box from '@mui/material/Box';
import { LineChart } from '@mui/x-charts/LineChart';
const sample = [1, 10, 30, 50, 70, 90, 100];
export default function MultipleAxes() {
return (
);
}
```
## Grouped axes
To group `band` or `point` axes together, provide a `groups` property in the axis definition.
This property expects an array of objects with a `getValue` function.
This feature is available for both x- and y-axes.
The `getValue` function receives the axis data value and should return a group name.
Each group name is used as-is, overriding any `valueFormatter` for the axis.
Groups are displayed in the order they're defined in the `groups` array.
### X-axis grouping
In the demo below, the x-axis is grouped by month, quarter, and year.
```tsx
import { BarChart } from '@mui/x-charts/BarChart';
export default function GroupedAxes() {
return (
);
}
const getMonth = (date: Date) =>
date.toLocaleDateString('en-US', { month: 'short' });
const getQuarter = (date: Date) => `Q${Math.floor(date.getMonth() / 3) + 1}`;
const getYear = (date: Date) =>
date.toLocaleDateString('en-US', { year: 'numeric' });
const valueFormatter = (v: Date) =>
v.toLocaleDateString('en-US', {
month: 'short',
year: 'numeric',
});
const data = [
new Date(2014, 11, 1),
new Date(2015, 0, 1),
new Date(2015, 1, 1),
new Date(2015, 2, 1),
new Date(2015, 3, 1),
new Date(2015, 4, 1),
new Date(2015, 5, 1),
new Date(2015, 6, 1),
new Date(2015, 7, 1),
new Date(2015, 8, 1),
new Date(2015, 9, 1),
new Date(2015, 10, 1),
new Date(2015, 11, 1),
new Date(2016, 0, 1),
];
const a = [
3190, 4000, 3000, 2000, 2780, 1890, 2390, 3490, 2400, 1398, 9800, 3908, 4800, 2040,
];
const b = [
1200, 2400, 1398, 9800, 3908, 4800, 3800, 4300, 2181, 2500, 2100, 3000, 2000, 2040,
];
const getPercents = (array: number[]) =>
array.map((v, index) => (100 * v) / (a[index] + b[index]));
const chartConfig = {
height: 200,
margin: { left: 0 },
series: [
{
data: getPercents(a),
label: 'Income',
valueFormatter: (value: number | null) => `${(value ?? 0).toFixed(0)}%`,
},
{
data: getPercents(b),
label: 'Expenses',
valueFormatter: (value: number | null) => `${(value ?? 0).toFixed(0)}%`,
},
],
yAxis: [
{
valueFormatter: (value: number | null) => `${(value ?? 0).toFixed(0)}%`,
},
],
} as const;
```
### Y-axis grouping
In the following demo, the y-axis is grouped by category and subcategory.
```tsx
import { BarChart } from '@mui/x-charts/BarChart';
export default function GroupedYAxes() {
return (
category[1] },
// Extract subcategory
{
getValue: (category) => category[0],
tickSize: 120,
tickLabelStyle: {
angle: -90,
textAnchor: 'middle',
},
},
],
valueFormatter: (value) => value.join(' - '),
},
]}
{...chartConfig}
/>
);
}
const categoryData = [
['Technology', 'Software'],
['Technology', 'Hardware'],
['Technology', 'AI/ML'],
['Finance', 'Banking'],
['Finance', 'Insurance'],
['Finance', 'Investment'],
['Healthcare', 'Pharmaceuticals'],
['Healthcare', 'Medical Devices'],
['Healthcare', 'Telemedicine'],
];
const salesData = [150, 120, 200, 180, 90, 160, 140, 110, 85];
const profitData = [45, 35, 80, 65, 25, 55, 50, 40, 30];
const chartConfig = {
height: 400,
xAxis: [{ valueFormatter: (value: number) => `${value}K` }],
series: [
{
data: salesData,
label: 'Sales',
valueFormatter: (value: number | null) => `${value}K`,
},
{
data: profitData,
label: 'Profit',
valueFormatter: (value: number | null) => `${value}K`,
},
],
};
```
### Tick size
You can customize the tick size for each group by providing a `tickSize` property in the `groups` array.
The `tickSize` also affects the tick label position.
Each item in the array corresponds to a group defined in the `getValue` function.
```tsx
import { BarChart } from '@mui/x-charts/BarChart';
export default function GroupedAxesTickSize() {
return (
);
}
const getMonth = (date: Date) =>
date.toLocaleDateString('en-US', { month: 'short' });
const formatQuarterYear = (date: Date) => {
const quarter = Math.floor(date.getMonth() / 3) + 1;
const year = date.getFullYear().toString().slice(-2);
return `Q${quarter} '${year}`;
};
const valueFormatter = (v: Date) =>
v.toLocaleDateString('en-US', {
month: 'short',
year: 'numeric',
});
const data = [
new Date(2015, 0, 1),
new Date(2015, 1, 1),
new Date(2015, 2, 1),
new Date(2015, 3, 1),
new Date(2015, 4, 1),
new Date(2015, 5, 1),
new Date(2015, 6, 1),
new Date(2015, 7, 1),
new Date(2015, 8, 1),
new Date(2015, 9, 1),
new Date(2015, 10, 1),
new Date(2015, 11, 1),
];
const a = [4000, 3000, 2000, 2780, 1890, 2390, 3490, 2400, 1398, 9800, 3908, 4800];
const b = [2400, 1398, 9800, 3908, 4800, 3800, 4300, 2181, 2500, 2100, 3000, 2000];
const getPercents = (array: number[]) =>
array.map((v, index) => (100 * v) / (a[index] + b[index]));
const chartConfig = {
height: 200,
margin: { left: 0 },
series: [
{
data: getPercents(a),
label: 'Income',
valueFormatter: (value: number | null) => `${(value ?? 0).toFixed(0)}%`,
},
{
data: getPercents(b),
label: 'Expenses',
valueFormatter: (value: number | null) => `${(value ?? 0).toFixed(0)}%`,
},
],
yAxis: [
{
valueFormatter: (value: number | null) => `${(value ?? 0).toFixed(0)}%`,
},
],
} as const;
```
### Styling grouped axes
To target a specific group, use the `data-group-index` attribute as a selector.
The example below has a yellow tick color for the last group and blue text for the first group.
```tsx
import { LineChart } from '@mui/x-charts/LineChart';
import { axisClasses } from '@mui/x-charts/ChartsAxis';
export default function GroupedAxesStyling() {
return (
);
}
const getMonth = (date: Date) =>
date.toLocaleDateString('en-US', { month: 'short' });
const formatQuarterYear = (date: Date) => {
const quarter = Math.floor(date.getMonth() / 3) + 1;
const year = date.getFullYear().toString().slice(-2);
return `Q${quarter} '${year}`;
};
const valueFormatter = (v: Date) =>
v.toLocaleDateString('en-US', {
month: 'short',
year: 'numeric',
});
const data = [
new Date(2015, 0, 1),
new Date(2015, 1, 1),
new Date(2015, 2, 1),
new Date(2015, 3, 1),
new Date(2015, 4, 1),
new Date(2015, 5, 1),
new Date(2015, 6, 1),
new Date(2015, 7, 1),
new Date(2015, 8, 1),
new Date(2015, 9, 1),
new Date(2015, 10, 1),
new Date(2015, 11, 1),
new Date(2016, 0, 1),
];
const a = [
4000, 3000, 2000, 2780, 1890, 2390, 3490, 2400, 1398, 9800, 3908, 4800, 2040,
];
const b = [
2400, 1398, 9800, 3908, 4800, 3800, 4300, 2181, 2500, 2100, 3000, 2000, 2040,
];
const getPercents = (array: number[]) =>
array.map((v, index) => (100 * v) / (a[index] + b[index]));
const chartConfig = {
height: 200,
margin: { left: 0 },
series: [
{
data: getPercents(a),
label: 'Income',
valueFormatter: (value: number | null) => `${(value ?? 0).toFixed(0)}%`,
},
{
data: getPercents(b),
label: 'Expenses',
valueFormatter: (value: number | null) => `${(value ?? 0).toFixed(0)}%`,
},
],
yAxis: [
{
valueFormatter: (value: number | null) => `${(value ?? 0).toFixed(0)}%`,
},
],
} as const;
```
## Axis customization
Beyond the axis definition, there are several other ways to further customize how axes are rendered:
### Styling axes by ID
To target a specific axis by its ID, use the `data-axis-id` attribute as a selector.
This is useful when you have multiple axes and want to style them differently.
In the example below, the revenue axis label is styled with a teal color and the profit axis label with a blue color to match their respective series.
```tsx
import * as React from 'react';
import { LineChart, type LineChartProps } from '@mui/x-charts/LineChart';
import { axisClasses } from '@mui/x-charts/ChartsAxis';
const years = [2010, 2011, 2012, 2013, 2014, 2015];
const revenue = [4000, 3000, 2000, 2780, 1890, 2390];
const profit = [24, 13, 98, 39, 48, 38];
const chartConfig: LineChartProps = {
xAxis: [{ data: years, scaleType: 'point' }],
yAxis: [
{ id: 'revenue-axis', label: 'Revenue ($)' },
{ id: 'profit-axis', label: 'Profit (%)', position: 'right' },
],
series: [
{ data: revenue, label: 'Revenue', yAxisId: 'revenue-axis', color: '#02b2af' },
{ data: profit, label: 'Profit', yAxisId: 'profit-axis', color: '#2e96ff' },
],
height: 300,
};
export default function AxisIdStyling() {
return (
);
}
```
### Fixing tick label overflow issues
When your tick labels are too long, they're clipped to avoid overflowing.
To reduce clipping due to overflow, you can [apply an angle to the tick labels](/x/react-charts/axis/#text-customization) or [increase the axis size](/x/react-charts/styling/#placement) to accommodate them.
In the demo below, the size of the x- and y-axes is modified to increase the space available for tick labels.
The first and last tick labels may bleed into the margin, and if that margin is not enough to display the label, it might be clipped.
To avoid this, you can use the `margin` prop to increase the space between the chart and the edge of the container.
```tsx
import * as React from 'react';
import Box from '@mui/material/Box';
import Stack from '@mui/material/Stack';
import FormControlLabel from '@mui/material/FormControlLabel';
import Checkbox from '@mui/material/Checkbox';
import { BarChart } from '@mui/x-charts/BarChart';
export default function MarginAndLabelPosition() {
const [fixMargin, setFixMargin] = React.useState(true);
return (
setFixMargin(event.target.checked)} />
}
label="Increase axes size"
labelPlacement="end"
/>
context.location === 'tick'
? value.split('').join('\n')
: usAirportPassengers.find((item) => item.code === value)!.fullName,
label: 'airports',
height: fixMargin ? 75 : undefined,
},
]}
// Other props
height={300}
dataset={usAirportPassengers}
series={[
{ dataKey: '2018', label: '2018' },
{ dataKey: '2019', label: '2019' },
{ dataKey: '2020', label: '2020' },
{ dataKey: '2021', label: '2021' },
{ dataKey: '2022', label: '2022' },
]}
hideLegend
yAxis={[
{
valueFormatter: (value: number) => `${(value / 1000).toLocaleString()}k`,
label: 'passengers',
width: fixMargin ? 85 : undefined,
},
]}
/>
);
}
const usAirportPassengers = [
{
fullName: 'Hartsfield–Jackson Atlanta International Airport',
code: 'ATL',
2022: 45396001,
2021: 36676010,
2020: 20559866,
2019: 53505795,
2018: 51865797,
},
{
fullName: 'Dallas/Fort Worth International Airport',
code: 'DFW',
2022: 35345138,
2021: 30005266,
2020: 18593421,
2019: 35778573,
2018: 32821799,
},
{
fullName: 'Denver International Airport',
code: 'DEN',
2022: 33773832,
2021: 28645527,
2020: 16243216,
2019: 33592945,
2018: 31362941,
},
{
fullName: "O'Hare International Airport",
code: 'ORD',
2022: 33120474,
2021: 26350976,
2020: 14606034,
2019: 40871223,
2018: 39873927,
},
{
fullName: 'Los Angeles International Airport',
code: 'LAX',
2022: 32326616,
2021: 23663410,
2020: 14055777,
2019: 42939104,
2018: 42624050,
},
{
fullName: 'John F. Kennedy International Airport',
code: 'JFK',
2022: 26919982,
2021: 15273342,
2020: 8269819,
2019: 31036655,
2018: 30620769,
},
{
fullName: 'Harry Reid International Airport',
code: 'LAS',
2022: 25480500,
2021: 19160342,
2020: 10584059,
2019: 24728361,
2018: 23795012,
},
{
fullName: 'Orlando International Airport',
code: 'MCO',
2022: 24469733,
2021: 19618838,
2020: 10467728,
2019: 24562271,
2018: 23202480,
},
{
fullName: 'Miami International Airport',
code: 'MIA',
2022: 23949892,
2021: 17500096,
2020: 8786007,
2019: 21421031,
2018: 21021640,
},
{
fullName: 'Charlotte Douglas International Airport',
code: 'CLT',
2022: 23100300,
2021: 20900875,
2020: 12952869,
2019: 24199688,
2018: 22281949,
},
{
fullName: 'Seattle–Tacoma International Airport',
code: 'SEA',
2022: 22157862,
2021: 17430195,
2020: 9462411,
2019: 25001762,
2018: 24024908,
},
{
fullName: 'Phoenix Sky Harbor International Airport',
code: 'PHX',
2022: 21852586,
2021: 18940287,
2020: 10531436,
2019: 22433552,
2018: 21622580,
},
{
fullName: 'Newark Liberty International Airport',
code: 'EWR',
2022: 21572147,
2021: 14514049,
2020: 7985474,
2019: 23160763,
2018: 22797602,
},
{
fullName: 'San Francisco International Airport',
code: 'SFO',
2022: 20411420,
2021: 11725347,
2020: 7745057,
2019: 27779230,
2018: 27790717,
},
{
fullName: 'George Bush Intercontinental Airport',
code: 'IAH',
2022: 19814052,
2021: 16242821,
2020: 8682558,
2019: 21905309,
2018: 21157398,
},
{
fullName: 'Logan International Airport',
code: 'BOS',
2022: 17443775,
2021: 10909817,
2020: 6035452,
2019: 20699377,
2018: 20006521,
},
{
fullName: 'Fort Lauderdale–Hollywood International Airport',
code: 'FLL',
2022: 15370165,
2021: 13598994,
2020: 8015744,
2019: 17950989,
2018: 17612331,
},
{
fullName: 'Minneapolis–Saint Paul International Airport',
code: 'MSP',
2022: 15242089,
2021: 12211409,
2020: 7069720,
2019: 19192917,
2018: 18361942,
},
{
fullName: 'LaGuardia Airport',
code: 'LGA',
2022: 14367463,
2021: 7827307,
2020: 4147116,
2019: 15393601,
2018: 15058501,
},
{
fullName: 'Detroit Metropolitan Airport',
code: 'DTW',
2022: 13751197,
2021: 11517696,
2020: 6822324,
2019: 18143040,
2018: 17436837,
},
];
```
### Rendering
The demo below illustrates all of the props available to customize axis rendering:
```tsx
import Box from '@mui/material/Box';
import ChartsUsageDemo from 'docsx/src/modules/components/ChartsUsageDemo';
import { ScatterChart } from '@mui/x-charts/ScatterChart';
import { Chance } from 'chance';
const chance = new Chance(42);
const data = Array.from({ length: 200 }, () => ({
x: chance.floating({ min: -25, max: 25 }),
y: chance.floating({ min: -25, max: 25 }),
})).map((d, index) => ({ ...d, id: index }));
const defaultXAxis = {
disableLine: false,
disableTicks: false,
fontSize: 12,
label: 'My axis',
tickSize: 6,
};
export default function AxisCustomization() {
return (
(
)}
getCode={({
props,
}) => `import { ScatterChart } from '@mui/x-charts/ScatterChart';
`}
/>
);
}
```
### Text customization
To customize the text elements (tick labels and axis labels), use the `tickLabelStyle` and `labelStyle` properties of the axis configuration.
When not set, the default values for the `textAnchor` and `dominantBaseline` properties depend on the value of the `angle` property.
You can test how these values behave and relate to one another in the demo below:
```tsx
import Box from '@mui/material/Box';
import ChartsUsageDemo from 'docsx/src/modules/components/ChartsUsageDemo';
import { BarChart } from '@mui/x-charts/BarChart';
import { dataset, valueFormatter } from '../dataset/weather';
const chartSetting = {
height: 300,
};
export default function AxisTextCustomization() {
return (
(
)}
getCode={({ props }) => `import { BarChart } from '@mui/x-charts/BarChart';
`}
/>
);
}
```
### Adding tick label icons
A `foreignObject` element can be used to render non-SVG elements inside SVGs. You can leverage this to create components that interact with the charts data. In the demo below, custom tick labels are built by displaying an icon below the text.
Bear in mind that using `foreignObject` might prevent charts from being [exported](/x/react-charts/export/).
```tsx
import * as React from 'react';
import Box from '@mui/material/Box';
import { ChartContainer } from '@mui/x-charts/ChartContainer';
import { BarPlot } from '@mui/x-charts/BarChart';
import { ChartsXAxis } from '@mui/x-charts/ChartsXAxis';
import { ChartsYAxis } from '@mui/x-charts/ChartsYAxis';
import { ChartsTextProps } from '@mui/x-charts/ChartsText';
import { iconMap } from '../dataset/company.icons';
function CustomTick(props: ChartsTextProps) {
const { x, y, text } = props;
const logo = iconMap[text];
return (
{logo && (
)}
);
}
export default function TickLabelImage() {
return (
);
}
```
## Symlog scale
A log scale cannot plot zero because log(0) is undefined.
To overcome this, you can use a symlog scale, which uses a linear scale for values close to zero and a logarithmic scale for the rest.
You can customize the value where the scale switches from linear to logarithmic using the `constant` property, which defaults to 1.
```tsx
import * as React from 'react';
import Stack from '@mui/material/Stack';
import ToggleButtonGroup from '@mui/material/ToggleButtonGroup';
import ToggleButton from '@mui/material/ToggleButton';
import { BarChart } from '@mui/x-charts/BarChart';
import { LineChart } from '@mui/x-charts/LineChart';
export default function SymlogScale() {
const [chartType, setChartType] = React.useState('bar');
const handleChartType = (event: any, newChartType: string) => {
if (newChartType !== null) {
setChartType(newChartType);
}
};
return (
{['bar', 'area'].map((type) => (
{type}
))}
{chartType === 'bar' && }
{chartType === 'area' && }
);
}
function SymlogBarChart() {
return (
);
}
function SymlogAreaChart() {
return (
);
}
```
## Composition
If you're using composition, you must provide the axis settings in the `` using the `xAxis` and `yAxis` props.
This provides all the scaling properties to its children, and lets you use the `` and `` components as children.
In turn, those components require an `axisId` prop to link them to an axis you defined in the ``.
You can choose their position with the `position` prop which accepts `'top'`/`'bottom'` for `` and `'left'`/`'right'` for ``.
The props described in the [rendering playground above](/x/react-charts/axis/#rendering) are also available.
```tsx
import Box from '@mui/material/Box';
import { ChartContainer } from '@mui/x-charts/ChartContainer';
import { LinePlot } from '@mui/x-charts/LineChart';
import { BarPlot } from '@mui/x-charts/BarChart';
import { ChartsXAxis } from '@mui/x-charts/ChartsXAxis';
import { ChartsYAxis } from '@mui/x-charts/ChartsYAxis';
export default function AxisWithComposition() {
return (
);
}
```
### Reference line
Use the `` component to add a reference line to a chart.
You can provide an `x` or a `y` prop for a vertical or horizontal line, respectively, at this value.
You can also add a `label` to this reference line, and position it using the `labelAlign` prop which accepts `'start'`, `'middle'`, and `'end'` values.
Elements can be styled with the `lineStyle` and `labelStyle` props.
```tsx
import Box from '@mui/material/Box';
import { ChartContainer } from '@mui/x-charts/ChartContainer';
import { LinePlot } from '@mui/x-charts/LineChart';
import { LineSeriesType } from '@mui/x-charts/models';
import { ChartsXAxis } from '@mui/x-charts/ChartsXAxis';
import { ChartsYAxis } from '@mui/x-charts/ChartsYAxis';
import { ChartsReferenceLine } from '@mui/x-charts/ChartsReferenceLine';
const timeData = [
new Date(2023, 7, 31),
new Date(2023, 7, 31, 12),
new Date(2023, 8, 1),
new Date(2023, 8, 1, 12),
new Date(2023, 8, 2),
new Date(2023, 8, 2, 12),
new Date(2023, 8, 3),
new Date(2023, 8, 3, 12),
new Date(2023, 8, 4),
];
const y1 = [5, 5, 10, 90, 85, 70, 30, 25, 25];
const y2 = [90, 85, 70, 25, 23, 40, 45, 40, 50];
const config = {
series: [
{ type: 'line', data: y1 },
{ type: 'line', data: y2 },
] as LineSeriesType[],
height: 400,
xAxis: [
{
data: timeData,
scaleType: 'time',
valueFormatter: (date: Date) =>
date.getHours() === 0
? date.toLocaleDateString('fr-FR', {
month: '2-digit',
day: '2-digit',
})
: date.toLocaleTimeString('fr-FR', {
hour: '2-digit',
}),
} as const,
],
};
export default function ReferenceLine() {
return (
);
}
```
---
# Source: https://mui.com/x/api/charts/bar-chart-premium.md
# BarChartPremium API
## Demos
For examples and details on the usage of this React component, visit the component demo pages:
- Charts - Range Bar
## Import
```jsx
import { BarChartPremium } from '@mui/x-charts-premium/BarChartPremium';
// or
import { BarChartPremium } from '@mui/x-charts-premium';
```
## Props
| Name | Type | Default | Required | Description |
|------|------|---------|----------|-------------|
| series | `Array