diff --git a/docs/data/charts/composition/PocBaseAndMaterial.js b/docs/data/charts/composition/PocBaseAndMaterial.js
new file mode 100644
index 0000000000000..bc952e645bbfd
--- /dev/null
+++ b/docs/data/charts/composition/PocBaseAndMaterial.js
@@ -0,0 +1,5 @@
+import * as React from 'react';
+
+export default function PocBaseAndMaterial() {
+ return
PocBaseAndMaterial
;
+}
diff --git a/docs/data/charts/composition/PocBaseAndMaterial.tsx b/docs/data/charts/composition/PocBaseAndMaterial.tsx
new file mode 100644
index 0000000000000..442d1ad7446e6
--- /dev/null
+++ b/docs/data/charts/composition/PocBaseAndMaterial.tsx
@@ -0,0 +1,58 @@
+import * as React from 'react';
+import { PieChart as PieChartBase } from '@mui/x-charts-base';
+import { PieChart as PieChartMaterial } from '@mui/x-charts-material';
+import type { PieChartProps } from '@mui/x-charts/PieChart';
+
+const data: PieChartProps = {
+ height: 300,
+ enableKeyboardNavigation: true,
+ series: [
+ {
+ arcLabel: 'value',
+ arcLabelMinAngle: 10,
+ innerRadius: '70%',
+ data: [
+ { value: 15, label: 'A' },
+ { value: 20, label: 'B' },
+ ],
+ },
+ {
+ outerRadius: '70%',
+ innerRadius: '40%',
+ cx: '100%',
+ startAngle: 180,
+ arcLabel: 'value',
+ data: [
+ { value: 15, label: 'D', color: 'rgb(135, 120, 255)' },
+ { value: 25, label: 'E', color: 'rgb(160, 143, 255)' },
+ { value: 35, label: 'F', color: 'rgb(185, 166, 255)' },
+ ],
+ },
+ {
+ outerRadius: '70%',
+ innerRadius: '40%',
+ cx: '0%',
+ endAngle: 180,
+ arcLabel: 'value',
+ data: [
+ { value: 15, label: 'D', color: 'rgb(255, 194, 163)' },
+ { value: 25, label: 'E', color: 'rgb(255, 186, 138)' },
+ { value: 35, label: 'F', color: 'rgb(255, 177, 112)' },
+ ],
+ },
+ ],
+};
+
+export default function PocBaseAndMaterial() {
+ return (
+
+ );
+}
diff --git a/docs/data/charts/composition/composition.md b/docs/data/charts/composition/composition.md
index 20c374d0dc1c3..27e477bc988d1 100644
--- a/docs/data/charts/composition/composition.md
+++ b/docs/data/charts/composition/composition.md
@@ -269,3 +269,12 @@ This example demonstrates how to combine scatter and line plots to overlay a nor
The bell curve is calculated based on the mean and standard deviation of the data.
{{"demo": "BellCurveOverlay.js" }}
+
+### POC: Base and Material UI packages
+
+This example demonstrates the proposed architecture where charts functionality is split into two packages:
+
+- **@mui/x-charts-base**: Framework-agnostic core with inline styles and a custom theme system
+- **@mui/x-charts-material**: Material UI integration layer using material components and theming
+
+{{"demo": "PocBaseAndMaterial.js" }}
diff --git a/packages/x-charts-base/package.json b/packages/x-charts-base/package.json
new file mode 100644
index 0000000000000..d8f2fd804a441
--- /dev/null
+++ b/packages/x-charts-base/package.json
@@ -0,0 +1,48 @@
+{
+ "name": "@mui/x-charts-base",
+ "version": "0.0.1",
+ "description": "Framework-agnostic base charting library for MUI X Charts",
+ "author": "MUI Team",
+ "main": "src/index.ts",
+ "license": "MIT",
+ "private": true,
+ "bugs": {
+ "url": "https://github.com/mui/mui-x/issues"
+ },
+ "homepage": "https://mui.com/x/react-charts/",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui-org"
+ },
+ "scripts": {
+ "build": "pnpm build:modern && pnpm build:node && pnpm build:stable && pnpm build:types && pnpm build:copy-files",
+ "build:modern": "node ../../scripts/build.mjs modern",
+ "build:node": "node ../../scripts/build.mjs node",
+ "build:stable": "node ../../scripts/build.mjs stable",
+ "build:copy-files": "node ../../scripts/copyFiles.mjs",
+ "build:types": "node ../../scripts/buildTypes.mjs",
+ "typescript": "tsc -p tsconfig.json"
+ },
+ "dependencies": {
+ "@babel/runtime": "catalog:",
+ "@mui/utils": "catalog:",
+ "@mui/material": "catalog:",
+ "@mui/x-charts-vendor": "workspace:^",
+ "@mui/x-internals": "workspace:^",
+ "@mui/x-charts": "workspace:^",
+ "clsx": "catalog:"
+ },
+ "peerDependencies": {
+ "react": "^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
+ },
+ "devDependencies": {},
+ "sideEffects": false,
+ "publishConfig": {
+ "access": "public",
+ "directory": "build"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
+}
diff --git a/packages/x-charts-base/src/ChartsSurface/ChartsSurface.tsx b/packages/x-charts-base/src/ChartsSurface/ChartsSurface.tsx
new file mode 100644
index 0000000000000..30df8d2635ada
--- /dev/null
+++ b/packages/x-charts-base/src/ChartsSurface/ChartsSurface.tsx
@@ -0,0 +1,74 @@
+'use client';
+import * as React from 'react';
+import useForkRef from '@mui/utils/useForkRef';
+import { useSvgRef } from '@mui/x-charts';
+import { ChartsAxesGradients } from '@mui/x-charts/internals/components/ChartsAxesGradients';
+import {
+ selectorChartSvgWidth,
+ selectorChartSvgHeight,
+ selectorChartPropsWidth,
+ selectorChartPropsHeight,
+} from '@mui/x-charts/internals/plugins/corePlugins/useChartDimensions';
+import {
+ selectorChartsIsKeyboardNavigationEnabled,
+ selectorChartsHasFocusedItem,
+} from '@mui/x-charts/internals/plugins/featurePlugins/useChartKeyboardNavigation';
+import { useSelector } from '@mui/x-charts/internals/store/useSelector';
+import clsx from 'clsx';
+import { useStore } from '@mui/x-charts/internals/store/useStore';
+
+export interface ChartsSurfaceProps
+ extends Omit<
+ React.SVGProps,
+ 'id' | 'children' | 'className' | 'height' | 'width' | 'cx' | 'cy' | 'viewBox' | 'color' | 'ref'
+ > {
+ className?: string;
+ title?: string;
+ desc?: string;
+ children?: React.ReactNode;
+}
+
+const ChartsSurface = React.forwardRef(function ChartsSurface(
+ inProps: ChartsSurfaceProps,
+ ref: React.Ref,
+) {
+ const store = useStore();
+
+ const svgWidth = useSelector(store, selectorChartSvgWidth);
+ const svgHeight = useSelector(store, selectorChartSvgHeight);
+
+ const propsWidth = useSelector(store, selectorChartPropsWidth);
+ const propsHeight = useSelector(store, selectorChartPropsHeight);
+ const isKeyboardNavigationEnabled = useSelector(store, selectorChartsIsKeyboardNavigationEnabled);
+ const hasFocusedItem = useSelector(store, selectorChartsHasFocusedItem);
+ const svgRef = useSvgRef();
+ const handleRef = useForkRef(svgRef, ref);
+
+ const { children, className, title, desc, ...other } = inProps;
+
+ const hasIntrinsicSize = svgHeight > 0 && svgWidth > 0;
+
+ const styles = {
+ ...(propsWidth ? { '--chart-surface-width': `${propsWidth}px` } : {}),
+ ...(propsHeight ? { '--chart-surface-height': `${propsHeight}px` } : {}),
+ } as React.CSSProperties;
+
+ return (
+
+ );
+});
+
+export { ChartsSurface };
diff --git a/packages/x-charts-base/src/ChartsSurface/index.ts b/packages/x-charts-base/src/ChartsSurface/index.ts
new file mode 100644
index 0000000000000..488a89f2528fb
--- /dev/null
+++ b/packages/x-charts-base/src/ChartsSurface/index.ts
@@ -0,0 +1 @@
+export * from './ChartsSurface';
diff --git a/packages/x-charts-base/src/FakeCss/index.ts b/packages/x-charts-base/src/FakeCss/index.ts
new file mode 100644
index 0000000000000..2dd5959b930f5
--- /dev/null
+++ b/packages/x-charts-base/src/FakeCss/index.ts
@@ -0,0 +1,49 @@
+import { styled } from '@mui/material';
+
+export const FakeCss = styled('div')(({ theme }) => ({
+ '& .ChartsSurface-root': {
+ height: 'var(--chart-surface-height, 100%)',
+ width: 'var(--chart-surface-width, 100%)',
+ display: 'flex',
+ position: 'relative',
+ flexDirection: 'column',
+ alignItems: 'center',
+ justifyContent: 'center',
+ overflow: 'hidden',
+ /* This prevents default touch actions when using the svg on mobile devices.
+ For example, prevent page scroll & zoom. */
+ touchAction: 'pan-y',
+ userSelect: 'none',
+ gridArea: 'chart',
+ },
+
+ '& .ChartsSurface-root:focus': {
+ outline: 'none', // By default don't show focus on the SVG container
+ },
+
+ '& .ChartsSurface-root:focus-visible': {
+ /* Show focus outline on the SVG container only when using keyboard navigation */
+ outline: 'var(--mui-palette-text-primary) solid 2px',
+ },
+
+ "& .ChartsSurface-root:focus-visible[data-has-focused-item='true']": {
+ /* But not if the chart has a focused children item */
+ outline: 'none',
+ },
+
+ "& .ChartsSurface-root [data-focused='true']": {
+ outline: 'var(--mui-palette-text-primary) solid 2px',
+ },
+
+ // @media doesn't work
+ '@media (prefers-color-scheme: dark)': {},
+
+ '--Primary-color': 'orange',
+
+ '--PieChart-arc-stroke': 'white',
+ ...theme.applyStyles('dark', {
+ '--PieChart-arc-stroke': 'black',
+ }),
+
+ '--FocusIndicator-color': 'var(--Primary-color)',
+}));
diff --git a/packages/x-charts-base/src/PieChart/PieArc.tsx b/packages/x-charts-base/src/PieChart/PieArc.tsx
new file mode 100644
index 0000000000000..3174f244a3884
--- /dev/null
+++ b/packages/x-charts-base/src/PieChart/PieArc.tsx
@@ -0,0 +1,95 @@
+'use client';
+import { type PieItemId } from '@mui/x-charts';
+import { useInteractionItemProps } from '@mui/x-charts/hooks/useInteractionItemProps';
+import clsx from 'clsx';
+import * as React from 'react';
+import { arc as d3Arc } from '@mui/x-charts-vendor/d3-shape';
+
+export type PieArcProps = Omit, 'ref' | 'id'> & {
+ cornerRadius: number;
+ endAngle: number;
+ innerRadius: number;
+ onClick?: (event: React.MouseEvent) => void;
+ outerRadius: number;
+ paddingAngle: number;
+ startAngle: number;
+ /**
+ * If `true`, the default event handlers are disabled.
+ * Those are used, for example, to display a tooltip or highlight the arc on hover.
+ */
+ skipInteraction?: boolean;
+ id: PieItemId;
+ dataIndex: number;
+ color: string;
+ isFaded: boolean;
+ isHighlighted: boolean;
+ isFocused: boolean;
+ stroke?: string;
+};
+
+const PieArc = React.forwardRef(function PieArc(props, ref) {
+ const {
+ className,
+ color,
+ dataIndex,
+ id,
+ isFaded,
+ isHighlighted,
+ isFocused,
+ onClick,
+ cornerRadius,
+ startAngle,
+ endAngle,
+ innerRadius,
+ outerRadius,
+ paddingAngle,
+ skipInteraction,
+ stroke,
+ ...other
+ } = props;
+
+ const interactionProps = useInteractionItemProps(
+ { type: 'pie', seriesId: id, dataIndex },
+ skipInteraction,
+ );
+ const p = {
+ cornerRadius,
+ startAngle,
+ endAngle,
+ innerRadius,
+ outerRadius,
+ paddingAngle,
+ };
+
+ const d = d3Arc().cornerRadius(p.cornerRadius)({
+ padAngle: p.paddingAngle,
+ innerRadius: p.innerRadius,
+ outerRadius: p.outerRadius,
+ startAngle: p.startAngle,
+ endAngle: p.endAngle,
+ })!;
+ const visibility = p.startAngle === p.endAngle ? ('hidden' as const) : ('visible' as const);
+
+ return (
+
+ );
+});
+
+export { PieArc };
diff --git a/packages/x-charts-base/src/PieChart/PieArcLabel.tsx b/packages/x-charts-base/src/PieChart/PieArcLabel.tsx
new file mode 100644
index 0000000000000..5f2d8c2082f8e
--- /dev/null
+++ b/packages/x-charts-base/src/PieChart/PieArcLabel.tsx
@@ -0,0 +1,66 @@
+'use client';
+import * as React from 'react';
+import { arc as d3Arc } from '@mui/x-charts-vendor/d3-shape';
+import { type PieItemId } from '@mui/x-charts';
+
+export type PieArcLabelProps = Omit, 'ref' | 'color' | 'id'> & {
+ startAngle: number;
+ endAngle: number;
+ innerRadius: number;
+ outerRadius: number;
+ arcLabelRadius: number;
+ cornerRadius: number;
+ paddingAngle: number;
+ formattedArcLabel?: string | null;
+ id: PieItemId;
+ color: string;
+ isFaded: boolean;
+ isHighlighted: boolean;
+};
+
+const PieArcLabel = React.forwardRef(
+ function PieArcLabel(props, ref) {
+ const {
+ id,
+ color,
+ startAngle,
+ endAngle,
+ paddingAngle,
+ arcLabelRadius,
+ innerRadius,
+ outerRadius,
+ cornerRadius,
+ formattedArcLabel,
+ isHighlighted,
+ isFaded,
+ style,
+ ...other
+ } = props;
+
+ const [x, y] = d3Arc().cornerRadius(cornerRadius).centroid({
+ padAngle: paddingAngle,
+ startAngle,
+ endAngle,
+ innerRadius,
+ outerRadius,
+ });
+
+ return (
+
+ {formattedArcLabel}
+
+ );
+ },
+);
+
+export { PieArcLabel };
diff --git a/packages/x-charts-base/src/PieChart/PieArcLabelPlot.tsx b/packages/x-charts-base/src/PieChart/PieArcLabelPlot.tsx
new file mode 100644
index 0000000000000..6944ac4d814ab
--- /dev/null
+++ b/packages/x-charts-base/src/PieChart/PieArcLabelPlot.tsx
@@ -0,0 +1,118 @@
+'use client';
+import {
+ type PieSeriesType,
+ type DefaultizedPieValueType,
+ type DefaultizedPieSeriesType,
+ type ComputedPieRadius,
+} from '@mui/x-charts';
+import { getLabel } from '@mui/x-charts/internals/getLabel';
+import { useTransformData } from '@mui/x-charts/PieChart/dataTransform/useTransformData';
+import { PieArcLabel } from './PieArcLabel';
+
+const RATIO = 180 / Math.PI;
+
+function getItemLabel(
+ arcLabel: PieSeriesType['arcLabel'],
+ arcLabelMinAngle: number,
+ item: DefaultizedPieValueType,
+) {
+ if (!arcLabel) {
+ return null;
+ }
+ const angle = (item.endAngle - item.startAngle) * RATIO;
+ if (angle < arcLabelMinAngle) {
+ return null;
+ }
+
+ switch (arcLabel) {
+ case 'label':
+ return getLabel(item.label, 'arc');
+ case 'value':
+ return item.value?.toString();
+ case 'formattedValue':
+ return item.formattedValue;
+ default:
+ return arcLabel({
+ ...item,
+ label: getLabel(item.label, 'arc'),
+ });
+ }
+}
+
+export interface PieArcLabelPlotProps
+ extends Pick<
+ DefaultizedPieSeriesType,
+ | 'data'
+ | 'faded'
+ | 'highlighted'
+ | 'cornerRadius'
+ | 'paddingAngle'
+ | 'arcLabel'
+ | 'arcLabelMinAngle'
+ | 'id'
+ >,
+ Pick, 'transform'>,
+ ComputedPieRadius {
+ /**
+ * Override the arc attributes when it is faded.
+ * @default { additionalRadius: -5 }
+ */
+ faded?: DefaultizedPieSeriesType['faded'];
+}
+
+function PieArcLabelPlot(props: PieArcLabelPlotProps) {
+ const {
+ arcLabel,
+ arcLabelMinAngle = 0,
+ arcLabelRadius,
+ cornerRadius = 0,
+ data,
+ faded = { additionalRadius: -5 },
+ highlighted,
+ id,
+ innerRadius,
+ outerRadius,
+ paddingAngle = 0,
+ ...other
+ } = props;
+
+ const transformedData = useTransformData({
+ innerRadius,
+ outerRadius,
+ arcLabelRadius,
+ cornerRadius,
+ paddingAngle,
+ id,
+ highlighted,
+ faded,
+ data,
+ });
+
+ if (data.length === 0) {
+ return null;
+ }
+
+ return (
+
+ {transformedData.map((item) => (
+
+ ))}
+
+ );
+}
+
+export { PieArcLabelPlot };
diff --git a/packages/x-charts-base/src/PieChart/PieArcPlot.tsx b/packages/x-charts-base/src/PieChart/PieArcPlot.tsx
new file mode 100644
index 0000000000000..4227e0024bb00
--- /dev/null
+++ b/packages/x-charts-base/src/PieChart/PieArcPlot.tsx
@@ -0,0 +1,125 @@
+'use client';
+import {
+ type DefaultizedPieSeriesType,
+ type ComputedPieRadius,
+ type PieItemIdentifier,
+ type DefaultizedPieValueType,
+} from '@mui/x-charts';
+import { useFocusedItem } from '@mui/x-charts/hooks/useFocusedItem';
+import { useTransformData } from '@mui/x-charts/PieChart/dataTransform/useTransformData';
+import * as React from 'react';
+import { PieArc } from './PieArc';
+
+export interface PieArcPlotProps
+ extends Pick<
+ DefaultizedPieSeriesType,
+ 'data' | 'faded' | 'highlighted' | 'cornerRadius' | 'paddingAngle' | 'id'
+ >,
+ Pick, 'transform'>,
+ ComputedPieRadius {
+ /**
+ * Override the arc attributes when it is faded.
+ * @default { additionalRadius: -5 }
+ */
+ faded?: DefaultizedPieSeriesType['faded'];
+ /**
+ * Callback fired when a pie item is clicked.
+ * @param {React.MouseEvent} event The event source of the callback.
+ * @param {PieItemIdentifier} pieItemIdentifier The pie item identifier.
+ * @param {DefaultizedPieValueType} item The pie item.
+ */
+ onItemClick?: (
+ event: React.MouseEvent,
+ pieItemIdentifier: PieItemIdentifier,
+ item: DefaultizedPieValueType,
+ ) => void;
+}
+
+function PieArcPlot(props: PieArcPlotProps) {
+ const {
+ innerRadius = 0,
+ outerRadius,
+ cornerRadius = 0,
+ paddingAngle = 0,
+ id,
+ highlighted,
+ faded = { additionalRadius: -5 },
+ data,
+ onItemClick,
+ ...other
+ } = props;
+
+ const transformedData = useTransformData({
+ innerRadius,
+ outerRadius,
+ cornerRadius,
+ paddingAngle,
+ id,
+ highlighted,
+ faded,
+ data,
+ });
+
+ const { dataIndex, seriesId, seriesType } = useFocusedItem() ?? {};
+ const focusedItem =
+ dataIndex !== undefined && seriesId === id && seriesType === 'pie'
+ ? transformedData[dataIndex]
+ : null;
+
+ if (data.length === 0) {
+ return null;
+ }
+
+ return (
+
+ {transformedData.map((item, index) => (
+ {
+ onItemClick(event, { type: 'pie', seriesId: id, dataIndex: index }, item);
+ })
+ }
+ />
+ ))}
+ {/* Render the focus indicator last, so it can align nicely over all arcs */}
+ {focusedItem && (
+
+ )}
+
+ );
+}
+
+export { PieArcPlot };
diff --git a/packages/x-charts-base/src/PieChart/PieChart.hooks.ts b/packages/x-charts-base/src/PieChart/PieChart.hooks.ts
new file mode 100644
index 0000000000000..b42951fadc70f
--- /dev/null
+++ b/packages/x-charts-base/src/PieChart/PieChart.hooks.ts
@@ -0,0 +1,75 @@
+import { getPieCoordinates } from '@mui/x-charts';
+import { getPercentageValue } from '@mui/x-charts/internals/getPercentageValue';
+import { selectorChartDrawingArea } from '@mui/x-charts/internals/plugins/corePlugins/useChartDimensions';
+import type { ProcessedSeries } from '@mui/x-charts/internals/plugins/corePlugins/useChartSeries';
+import { selectorAllSeriesOfType } from '@mui/x-charts/internals/seriesSelectorOfType';
+import { useSelector } from '@mui/x-charts/internals/store/useSelector';
+import { useStore } from '@mui/x-charts/internals/store/useStore';
+import { createSelector } from '@mui/x-internals/store';
+
+const pieSelector = (store: any) => selectorAllSeriesOfType(store, 'pie') as ProcessedSeries['pie'];
+
+const selectorPieSeriesData = createSelector(
+ pieSelector,
+ selectorChartDrawingArea,
+ (pieSeries, drawingArea) => {
+ if (!pieSeries) {
+ return null;
+ }
+
+ const { width, height, left, top } = drawingArea;
+
+ const { series, seriesOrder } = pieSeries;
+
+ return seriesOrder.map((seriesId) => {
+ const {
+ innerRadius: innerRadiusParam,
+ outerRadius: outerRadiusParam,
+ arcLabelRadius: arcLabelRadiusParam,
+ cornerRadius,
+ paddingAngle,
+ arcLabel,
+ arcLabelMinAngle,
+ data,
+ highlighted,
+ faded,
+ cx: cxParam,
+ cy: cyParam,
+ } = series[seriesId];
+
+ const { cx, cy, availableRadius } = getPieCoordinates(
+ { cx: cxParam, cy: cyParam },
+ { width, height },
+ );
+ const outerRadius = getPercentageValue(outerRadiusParam ?? availableRadius, availableRadius);
+ const innerRadius = getPercentageValue(innerRadiusParam ?? 0, availableRadius);
+
+ const arcLabelRadius =
+ arcLabelRadiusParam === undefined
+ ? (outerRadius + innerRadius) / 2
+ : getPercentageValue(arcLabelRadiusParam, availableRadius);
+ return {
+ innerRadius,
+ outerRadius,
+ cornerRadius,
+ paddingAngle,
+ id: seriesId,
+ data,
+ highlighted,
+ faded,
+ arcLabelRadius,
+ arcLabel,
+ arcLabelMinAngle,
+ availableRadius,
+ cx,
+ cy,
+ transform: `translate(${left + cx}, ${top + cy})`,
+ };
+ });
+ },
+);
+
+export const usePiePlotData = () => {
+ const store = useStore();
+ return useSelector(store, selectorPieSeriesData);
+};
diff --git a/packages/x-charts-base/src/PieChart/PieChart.parts.ts b/packages/x-charts-base/src/PieChart/PieChart.parts.ts
new file mode 100644
index 0000000000000..dc78a9d73a85b
--- /dev/null
+++ b/packages/x-charts-base/src/PieChart/PieChart.parts.ts
@@ -0,0 +1 @@
+export * as PieChart from './PieChart';
diff --git a/packages/x-charts-base/src/PieChart/PieChart.tsx b/packages/x-charts-base/src/PieChart/PieChart.tsx
new file mode 100644
index 0000000000000..195f42564b49d
--- /dev/null
+++ b/packages/x-charts-base/src/PieChart/PieChart.tsx
@@ -0,0 +1,97 @@
+import {
+ ChartDataProvider,
+ PIE_CHART_PLUGINS,
+ type ChartDataProviderProps,
+ type PieChartPluginSignatures,
+ type PiePlotProps,
+ type PieSeriesType,
+ type PieValueType,
+} from '@mui/x-charts';
+import type { MakeOptional } from '@mui/x-internals/types';
+import type { ChartsOverlayProps } from '@mui/x-charts/ChartsOverlay';
+import * as React from 'react';
+import { defaultizeMargin } from '@mui/x-charts/internals/defaultizeMargin';
+import { DEFAULT_PIE_CHART_MARGIN } from '@mui/x-charts/internals/constants';
+import { useChartContainerProps } from '@mui/x-charts/ChartContainer/useChartContainerProps';
+import { FakeCss } from '../FakeCss';
+import { ChartsSurface } from '../ChartsSurface';
+import { PiePlot } from './PiePlot';
+import { PieLabelPlot } from './PieLabelPlot';
+
+export type PieSeries = MakeOptional>, 'type'>;
+export interface PieRootProps
+ extends Omit<
+ ChartDataProviderProps<'pie', PieChartPluginSignatures>,
+ 'series' | 'slots' | 'slotProps' | 'experimentalFeatures'
+ >,
+ Omit {
+ /**
+ * The series to display in the pie chart.
+ * An array of [[PieSeries]] objects.
+ */
+ series: Readonly;
+ /**
+ * If `true`, the legend is not rendered.
+ */
+ hideLegend?: boolean;
+ /**
+ * Callback fired when a pie arc is clicked.
+ */
+ onItemClick?: PiePlotProps['onItemClick'];
+ /**
+ * If true, shows the default chart toolbar.
+ * @default false
+ */
+ showToolbar?: boolean;
+}
+
+const PieRoot = React.forwardRef(function PieChart(
+ props: PieRootProps,
+ ref: React.Ref,
+) {
+ const {
+ series,
+ width,
+ height,
+ margin: marginProps,
+ colors,
+ skipAnimation,
+ hideLegend,
+ children,
+ onItemClick,
+ loading,
+ highlightedItem,
+ onHighlightChange,
+ showToolbar,
+ ...other
+ } = props;
+ const margin = defaultizeMargin(marginProps, DEFAULT_PIE_CHART_MARGIN);
+
+ const { chartDataProviderProps } = useChartContainerProps<'pie', PieChartPluginSignatures>(
+ {
+ ...other,
+ series: series.map((s) => ({ type: 'pie', ...s })),
+ width,
+ height,
+ margin,
+ colors,
+ highlightedItem,
+ onHighlightChange,
+ skipAnimation,
+ plugins: PIE_CHART_PLUGINS,
+ },
+ ref,
+ );
+
+ return (
+ {...chartDataProviderProps}>
+ {children}
+
+ );
+});
+
+// We could use `ChartsSurface` directly, but I think we could propose a different pattern, like if you want a single chart, then
+// you can use `PieChart.Surface`, but if you want composition, we could use like `Composition.Surface`, technically they are the same though.
+const PieSurface = ChartsSurface;
+
+export { PieRoot as Root, PieSurface as Surface, PiePlot as Plot, PieLabelPlot as LabelPlot };
diff --git a/packages/x-charts-base/src/PieChart/PieLabelPlot.tsx b/packages/x-charts-base/src/PieChart/PieLabelPlot.tsx
new file mode 100644
index 0000000000000..d19d1ab86fa5c
--- /dev/null
+++ b/packages/x-charts-base/src/PieChart/PieLabelPlot.tsx
@@ -0,0 +1,41 @@
+'use client';
+
+import { PieArcLabelPlot } from './PieArcLabelPlot';
+import { usePiePlotData } from './PieChart.hooks';
+
+function PieLabelPlot() {
+ const plotData = usePiePlotData();
+
+ return plotData?.map((seriesData) => {
+ const {
+ innerRadius,
+ outerRadius,
+ cornerRadius,
+ paddingAngle,
+ data,
+ availableRadius,
+ arcLabelRadius,
+ id,
+ arcLabel,
+ arcLabelMinAngle,
+ transform,
+ } = seriesData;
+
+ return (
+
+ );
+ });
+}
+
+export { PieLabelPlot };
diff --git a/packages/x-charts-base/src/PieChart/PiePlot.tsx b/packages/x-charts-base/src/PieChart/PiePlot.tsx
new file mode 100644
index 0000000000000..0bdce1f62e62b
--- /dev/null
+++ b/packages/x-charts-base/src/PieChart/PiePlot.tsx
@@ -0,0 +1,43 @@
+'use client';
+
+import { type PieArcPlotProps } from '@mui/x-charts';
+import { PieArcPlot } from './PieArcPlot';
+import { usePiePlotData } from './PieChart.hooks';
+
+export interface PiePlotProps extends Pick {}
+
+function PiePlot(props: PiePlotProps) {
+ const { onItemClick } = props;
+ const plotData = usePiePlotData();
+
+ return plotData?.map((seriesData) => {
+ const {
+ innerRadius,
+ outerRadius,
+ cornerRadius,
+ paddingAngle,
+ data,
+ highlighted,
+ faded,
+ id,
+ transform,
+ } = seriesData;
+
+ return (
+
+ );
+ });
+}
+
+export { PiePlot };
diff --git a/packages/x-charts-base/src/PieChart/index.ts b/packages/x-charts-base/src/PieChart/index.ts
new file mode 100644
index 0000000000000..2f0fc927e8104
--- /dev/null
+++ b/packages/x-charts-base/src/PieChart/index.ts
@@ -0,0 +1 @@
+export * from './PieChart.parts';
diff --git a/packages/x-charts-base/src/index.ts b/packages/x-charts-base/src/index.ts
new file mode 100644
index 0000000000000..52ee2cdcbd0d8
--- /dev/null
+++ b/packages/x-charts-base/src/index.ts
@@ -0,0 +1,2 @@
+export * from './PieChart';
+export * from './ChartsSurface';
diff --git a/packages/x-charts-base/tsconfig.json b/packages/x-charts-base/tsconfig.json
new file mode 100644
index 0000000000000..d4efb5ec64421
--- /dev/null
+++ b/packages/x-charts-base/tsconfig.json
@@ -0,0 +1,7 @@
+{
+ "extends": "../../tsconfig.json",
+ "compilerOptions": {
+ "types": ["node"]
+ },
+ "include": ["src/**/*"]
+}
diff --git a/packages/x-charts-material/package.json b/packages/x-charts-material/package.json
new file mode 100644
index 0000000000000..1bb7b790c366c
--- /dev/null
+++ b/packages/x-charts-material/package.json
@@ -0,0 +1,48 @@
+{
+ "name": "@mui/x-charts-material",
+ "version": "0.0.1",
+ "description": "Material UI integration for @mui/x-charts-base",
+ "author": "MUI Team",
+ "main": "src/index.ts",
+ "license": "MIT",
+ "private": true,
+ "bugs": {
+ "url": "https://github.com/mui/mui-x/issues"
+ },
+ "homepage": "https://mui.com/x/react-charts/",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui-org"
+ },
+ "scripts": {
+ "build": "pnpm build:modern && pnpm build:node && pnpm build:stable && pnpm build:types && pnpm build:copy-files",
+ "build:modern": "node ../../scripts/build.mjs modern",
+ "build:node": "node ../../scripts/build.mjs node",
+ "build:stable": "node ../../scripts/build.mjs stable",
+ "build:copy-files": "node ../../scripts/copyFiles.mjs",
+ "build:types": "node ../../scripts/buildTypes.mjs",
+ "typescript": "tsc -p tsconfig.json"
+ },
+ "dependencies": {
+ "@babel/runtime": "catalog:",
+ "@mui/material": "catalog:",
+ "@mui/utils": "catalog:",
+ "@mui/x-charts-base": "workspace:^",
+ "@mui/x-internals": "workspace:^",
+ "clsx": "catalog:"
+ },
+ "peerDependencies": {
+ "@emotion/react": "^11.13.3",
+ "@emotion/styled": "^11.13.0",
+ "react": "^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
+ },
+ "sideEffects": false,
+ "publishConfig": {
+ "access": "public",
+ "directory": "build"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
+}
diff --git a/packages/x-charts-material/src/ChartsSurface/ChartsSurface.tsx b/packages/x-charts-material/src/ChartsSurface/ChartsSurface.tsx
new file mode 100644
index 0000000000000..945b190e416a8
--- /dev/null
+++ b/packages/x-charts-material/src/ChartsSurface/ChartsSurface.tsx
@@ -0,0 +1,4 @@
+import { styled } from '@mui/material/styles';
+import { ChartsSurface as BaseSurface } from '@mui/x-charts-base/ChartsSurface';
+
+export const ChartsSurface = styled(BaseSurface)();
diff --git a/packages/x-charts-material/src/ChartsTooltip/ChartsTooltip.tsx b/packages/x-charts-material/src/ChartsTooltip/ChartsTooltip.tsx
new file mode 100644
index 0000000000000..3656aee74f3be
--- /dev/null
+++ b/packages/x-charts-material/src/ChartsTooltip/ChartsTooltip.tsx
@@ -0,0 +1,12 @@
+'use client';
+import {
+ // This is coming from x-charts but would be in this package for simplicity
+ ChartsTooltip as MaterialChartsTooltip,
+ type ChartsTooltipProps,
+} from '@mui/x-charts/ChartsTooltip';
+
+function ChartsTooltip(props: ChartsTooltipProps) {
+ return ;
+}
+
+export { ChartsTooltip };
diff --git a/packages/x-charts-material/src/ChartsTooltip/index.ts b/packages/x-charts-material/src/ChartsTooltip/index.ts
new file mode 100644
index 0000000000000..392e33dcbde2b
--- /dev/null
+++ b/packages/x-charts-material/src/ChartsTooltip/index.ts
@@ -0,0 +1 @@
+export * from './ChartsTooltip';
diff --git a/packages/x-charts-material/src/FakeCss/index.ts b/packages/x-charts-material/src/FakeCss/index.ts
new file mode 100644
index 0000000000000..6db00ca4f4957
--- /dev/null
+++ b/packages/x-charts-material/src/FakeCss/index.ts
@@ -0,0 +1,9 @@
+import { styled } from '@mui/material';
+
+export const FakeCss = styled('div')(({ theme }) => ({
+ '--Primary-color': theme.palette.primary.main,
+
+ '--PieChart-arc-stroke': theme.palette.background.paper,
+
+ '--FocusIndicator-color': 'var(--Primary-color)',
+}));
diff --git a/packages/x-charts-material/src/PieChart/PieChart.tsx b/packages/x-charts-material/src/PieChart/PieChart.tsx
new file mode 100644
index 0000000000000..520ca6b8f937e
--- /dev/null
+++ b/packages/x-charts-material/src/PieChart/PieChart.tsx
@@ -0,0 +1,25 @@
+import * as React from 'react';
+import { PieChartProps } from '@mui/x-charts';
+import { PieChart as PieChartBase } from '@mui/x-charts-base';
+import { ChartsSurface } from '../ChartsSurface/ChartsSurface';
+import { ChartsTooltip } from '../ChartsTooltip';
+import { FakeCss } from '../FakeCss';
+
+export const PieChart = React.forwardRef(function PieChart(
+ props: PieChartProps,
+ ref: React.Ref,
+) {
+ const { title, desc, sx, ...other } = props;
+
+ return (
+
+
+
+
+
+
+
+
+
+ );
+});
diff --git a/packages/x-charts-material/src/PieChart/index.ts b/packages/x-charts-material/src/PieChart/index.ts
new file mode 100644
index 0000000000000..4ffd151ee3038
--- /dev/null
+++ b/packages/x-charts-material/src/PieChart/index.ts
@@ -0,0 +1 @@
+export * from './PieChart';
diff --git a/packages/x-charts-material/src/index.ts b/packages/x-charts-material/src/index.ts
new file mode 100644
index 0000000000000..4ffd151ee3038
--- /dev/null
+++ b/packages/x-charts-material/src/index.ts
@@ -0,0 +1 @@
+export * from './PieChart';
diff --git a/packages/x-charts-material/tsconfig.json b/packages/x-charts-material/tsconfig.json
new file mode 100644
index 0000000000000..d4efb5ec64421
--- /dev/null
+++ b/packages/x-charts-material/tsconfig.json
@@ -0,0 +1,7 @@
+{
+ "extends": "../../tsconfig.json",
+ "compilerOptions": {
+ "types": ["node"]
+ },
+ "include": ["src/**/*"]
+}
diff --git a/packages/x-charts/src/internals/seriesSelectorOfType.ts b/packages/x-charts/src/internals/seriesSelectorOfType.ts
index df4b37c42dd0e..70aa7c5df18e1 100644
--- a/packages/x-charts/src/internals/seriesSelectorOfType.ts
+++ b/packages/x-charts/src/internals/seriesSelectorOfType.ts
@@ -9,8 +9,7 @@ import { useSelector } from './store/useSelector';
export const selectorAllSeriesOfType = createSelector(
selectorChartSeriesProcessed,
- (processedSeries: ProcessedSeries, seriesType: T) =>
- processedSeries[seriesType],
+ (processedSeries, seriesType: keyof ChartsSeriesConfig) => processedSeries[seriesType],
);
export const selectorSeriesOfType = createSelectorMemoized(
@@ -32,7 +31,7 @@ export const selectorSeriesOfType = createSelectorMemoized(
return processedSeries[seriesType]?.series?.[ids];
}
- const result: ChartSeriesDefaultized[] = [];
+ const result: ChartSeriesDefaultized[] = [];
const failedIds: SeriesId[] = [];
for (const id of ids) {
const series = processedSeries[seriesType]?.series?.[id];
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 9e3876a5c19ef..42f98cad096c7 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -912,6 +912,71 @@ importers:
version: 6.1.2
publishDirectory: build
+ packages/x-charts-base:
+ dependencies:
+ '@babel/runtime':
+ specifier: 'catalog:'
+ version: 7.28.4
+ '@mui/material':
+ specifier: 'catalog:'
+ version: 7.3.5(@emotion/react@11.14.0(@types/react@19.2.7)(react@19.2.0))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.7)(react@19.2.0))(@types/react@19.2.7)(react@19.2.0))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@mui/utils':
+ specifier: 'catalog:'
+ version: 7.3.5(@types/react@19.2.7)(react@19.2.0)
+ '@mui/x-charts':
+ specifier: workspace:^
+ version: link:../x-charts/build
+ '@mui/x-charts-vendor':
+ specifier: workspace:^
+ version: link:../x-charts-vendor
+ '@mui/x-internals':
+ specifier: workspace:^
+ version: link:../x-internals/build
+ clsx:
+ specifier: 'catalog:'
+ version: 2.1.1
+ react:
+ specifier: ^17.0.0 || ^18.0.0 || ^19.0.0
+ version: 19.2.0
+ react-dom:
+ specifier: ^17.0.0 || ^18.0.0 || ^19.0.0
+ version: 19.2.0(react@19.2.0)
+ publishDirectory: build
+
+ packages/x-charts-material:
+ dependencies:
+ '@babel/runtime':
+ specifier: 'catalog:'
+ version: 7.28.4
+ '@emotion/react':
+ specifier: ^11.13.3
+ version: 11.14.0(@types/react@19.2.7)(react@19.2.0)
+ '@emotion/styled':
+ specifier: ^11.13.0
+ version: 11.14.1(@emotion/react@11.14.0(@types/react@19.2.7)(react@19.2.0))(@types/react@19.2.7)(react@19.2.0)
+ '@mui/material':
+ specifier: 'catalog:'
+ version: 7.3.5(@emotion/react@11.14.0(@types/react@19.2.7)(react@19.2.0))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.7)(react@19.2.0))(@types/react@19.2.7)(react@19.2.0))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@mui/utils':
+ specifier: 'catalog:'
+ version: 7.3.5(@types/react@19.2.7)(react@19.2.0)
+ '@mui/x-charts-base':
+ specifier: workspace:^
+ version: link:../x-charts-base/build
+ '@mui/x-internals':
+ specifier: workspace:^
+ version: link:../x-internals/build
+ clsx:
+ specifier: 'catalog:'
+ version: 2.1.1
+ react:
+ specifier: ^17.0.0 || ^18.0.0 || ^19.0.0
+ version: 19.2.0
+ react-dom:
+ specifier: ^17.0.0 || ^18.0.0 || ^19.0.0
+ version: 19.2.0(react@19.2.0)
+ publishDirectory: build
+
packages/x-charts-premium:
dependencies:
'@babel/runtime':
diff --git a/tsconfig.json b/tsconfig.json
index 16252f2118fa2..c209febac8558 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -27,6 +27,10 @@
"@mui/x-date-pickers-pro/*": ["./packages/x-date-pickers-pro/src/*"],
"@mui/x-charts": ["./packages/x-charts/src"],
"@mui/x-charts/*": ["./packages/x-charts/src/*"],
+ "@mui/x-charts-base": ["./packages/x-charts-base/src"],
+ "@mui/x-charts-base/*": ["./packages/x-charts-base/src/*"],
+ "@mui/x-charts-material": ["./packages/x-charts-material/src"],
+ "@mui/x-charts-material/*": ["./packages/x-charts-material/src/*"],
"@mui/x-charts-pro": ["./packages/x-charts-pro/src"],
"@mui/x-charts-pro/*": ["./packages/x-charts-pro/src/*"],
"@mui/x-charts-premium": ["./packages/x-charts-premium/src"],