diff --git a/docs/data/base/components/accordion/UnstyledAccordionIntroduction.js b/docs/data/base/components/accordion/UnstyledAccordionIntroduction.js
new file mode 100644
index 0000000000..dcfddb6413
--- /dev/null
+++ b/docs/data/base/components/accordion/UnstyledAccordionIntroduction.js
@@ -0,0 +1,135 @@
+import * as React from 'react';
+import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
+import * as Accordion from '@base_ui/react/Accordion';
+
+export default function UnstyledAccordionIntroduction() {
+ return (
+
+
+
+
+
+ Trigger 1
+
+
+
+
+ This is the contents of Accordion.Panel 1
+
+
+
+
+
+ Trigger 2
+
+
+
+
+ This is the contents of Accordion.Panel 2
+
+
+
+
+
+ Trigger 3
+
+
+
+
+ This is the contents of Accordion.Panel 3
+
+
+
+
+
+ );
+}
+
+function Styles() {
+ return (
+
+ );
+}
diff --git a/docs/data/base/components/accordion/UnstyledAccordionIntroduction.tsx b/docs/data/base/components/accordion/UnstyledAccordionIntroduction.tsx
new file mode 100644
index 0000000000..dcfddb6413
--- /dev/null
+++ b/docs/data/base/components/accordion/UnstyledAccordionIntroduction.tsx
@@ -0,0 +1,135 @@
+import * as React from 'react';
+import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
+import * as Accordion from '@base_ui/react/Accordion';
+
+export default function UnstyledAccordionIntroduction() {
+ return (
+
+
+
+
+
+ Trigger 1
+
+
+
+
+ This is the contents of Accordion.Panel 1
+
+
+
+
+
+ Trigger 2
+
+
+
+
+ This is the contents of Accordion.Panel 2
+
+
+
+
+
+ Trigger 3
+
+
+
+
+ This is the contents of Accordion.Panel 3
+
+
+
+
+
+ );
+}
+
+function Styles() {
+ return (
+
+ );
+}
diff --git a/docs/data/base/components/accordion/accordion.md b/docs/data/base/components/accordion/accordion.md
index 96b8af2955..08d86d4335 100644
--- a/docs/data/base/components/accordion/accordion.md
+++ b/docs/data/base/components/accordion/accordion.md
@@ -11,3 +11,246 @@ packageName: '@base_ui/react'
# Accordion
Accordion is a stacked set of interactive headings that each reveal an associated section of content.
+
+{{"component": "@mui/docs/ComponentLinkHeader", "design": false}}
+
+{{"component": "modules/components/ComponentPageTabs.js"}}
+
+## Introduction
+
+{{"demo": "UnstyledAccordionIntroduction.js", "defaultCodeOpen": false, "bg": "gradient"}}
+
+## Installation
+
+Base UI components are all available as a single package.
+
+
+
+```bash npm
+npm install @base_ui/react
+```
+
+```bash yarn
+yarn add @base_ui/react
+```
+
+```bash pnpm
+pnpm add @base_ui/react
+```
+
+
+
+Once you have the package installed, import the components.
+
+```ts
+import * as Accordion from '@base_ui/react/Accordion';
+```
+
+## Anatomy
+
+Accordions are implemented using a collection of related components:
+
+- `` is a top-level component that wraps the other components.
+- `` is a component that wraps each section of content
+- `` is a button that toggles the open state of it's section
+- `` is an element that wraps the `Trigger`
+- `` is the element that contains content in a `Section`
+
+```tsx
+
+
+
+
+ Toggle one
+
+
+
+ Section one content
+
+
+
+
+
+ Toggle two
+
+
+
+ Section two content
+
+
+
+```
+
+## Value
+
+Each `Accordion.Section` is represented by a value, which by default is its zero-based index by DOM position.
+The first section has an implicit `value` of `0`, the second section has a `value` of `1`, and so on.
+
+The open state of the accordion is represented an array holding the `value`s of all open `Section`s.
+
+You can optionally specify a custom `value` prop on `Section`:
+
+```tsx
+
+
+
+
+ Toggle one
+
+
+
+ Section one content
+
+
+
+
+
+ Toggle two
+
+
+
+ Section two content
+
+
+
+```
+
+### Default value
+
+When uncontrolled, use the `defaultValue` prop to set the initial state of the accordion:
+
+```tsx
+
+ {/* `value={0}` by default */}
+
+
+ Toggle one
+
+
+
+ Section one content
+
+
+ {/* `value={1}` by default */}
+
+
+ Toggle two
+
+
+
+ Section two content
+
+
+
+
+{/* with custom `value`s */}
+
+
+
+
+ Toggle one
+
+
+
+ Section one content
+
+
+
+
+
+ Toggle two
+
+
+
+ Section two content
+
+
+
+```
+
+### Controlled
+
+When controlled, pass the `value` and `onOpenChange` props to `Accordion.Root`:
+
+```tsx
+const [value, setValue] = React.useState(['a']);
+
+return (
+
+
+
+
+ Toggle one
+
+
+
+ Section one content
+
+
+
+
+
+ Toggle two
+
+
+
+ Section two content
+
+
+
+)
+```
+
+## Customization
+
+### Only one section open at a time
+
+By default, all accordion sections can be opened at the same time. Use the `openMultiple` prop to only allow one open section at a time:
+
+```tsx
+
+ {/* subcomponents */}
+
+```
+
+### At least one section remains open
+
+Use controlled mode to always keep one section open:
+
+```tsx
+const [value, setValue] = React.useState([0]);
+
+const handleOpenChange = (newValue) => {
+ if (newValue.length > 0) {
+ setValue(newValue)
+ }
+}
+
+return (
+
+ {/* subcomponents */}
+
+)
+```
+
+## Horizontal
+
+Use the `orientation` prop to configure a horizontal accordion. In a horizontal accordion, focus will move between `Accordion.Trigger`s with the Right Arrow and Left Arrow keys, instead of Down/Up.
+
+```tsx
+
+ {/* subcomponents */}
+
+```
+
+## RTL
+
+Use the `direction` prop to configure a RTL accordion:
+
+```tsx
+
+ {/* subcomponents */}
+
+```
+
+When a horizontal accordion is set to `direction="rtl"`, keyboard actions are reversed accordingly - Left Arrow moves focus to the next trigger and Right Arrow moves focus to the previous trigger.
diff --git a/docs/pages/experiments/accordion-horizontal.tsx b/docs/pages/experiments/accordion-horizontal.tsx
new file mode 100644
index 0000000000..96e1f02ff2
--- /dev/null
+++ b/docs/pages/experiments/accordion-horizontal.tsx
@@ -0,0 +1,179 @@
+import * as React from 'react';
+import * as Accordion from '@base_ui/react/Accordion';
+
+function classNames(...classes: Array) {
+ return classes.filter(Boolean).join(' ');
+}
+
+export default function App() {
+ const [val, setVal] = React.useState(['one']);
+ return (
+
+
Horizontal LTR
+
+ {['one', 'two', 'three'].map((value, index) => (
+
+
+
+ {index + 1}
+ {value}
+
+
+
+ This is the contents of Accordion.Panel {index + 1}
+
+
+ ))}
+
+
+
+ Horizontal RTL
+ one section must remain open
+
+
{
+ if (newValue.length > 0) {
+ setVal(newValue);
+ }
+ }}
+ >
+ {['one', 'two', 'three'].map((value, index) => (
+
+
+
+ {index + 1}
+ {value}
+
+
+
+ This is the contents of Accordion.Panel {index + 1}
+
+
+ ))}
+
+
+
+ );
+}
+
+function HorizontalStyles() {
+ return (
+
+ );
+}
diff --git a/docs/pages/experiments/accordion-material.tsx b/docs/pages/experiments/accordion-material.tsx
new file mode 100644
index 0000000000..3130c291ac
--- /dev/null
+++ b/docs/pages/experiments/accordion-material.tsx
@@ -0,0 +1,108 @@
+import * as React from 'react';
+import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
+import * as Accordion from '@base_ui/react/Accordion';
+
+export default function App() {
+ return (
+
+
+ {[0, 1, 2, 3].map((index) => (
+
+
+
+ Trigger {index + 1}
+
+
+
+
+ This is the contents of Accordion.Panel {index + 1}
+
+
+ ))}
+
+
+
+ );
+}
+
+function MaterialStyles() {
+ return (
+
+ );
+}
diff --git a/docs/pages/experiments/accordion.tsx b/docs/pages/experiments/accordion.tsx
index 94e537a392..eb194c65c7 100644
--- a/docs/pages/experiments/accordion.tsx
+++ b/docs/pages/experiments/accordion.tsx
@@ -1,12 +1,13 @@
import * as React from 'react';
import Check from '@mui/icons-material/Check';
-import { useTheme } from '@mui/system';
+// import { useTheme } from '@mui/system';
import * as Checkbox from '@base_ui/react/Checkbox';
import * as Accordion from '@base_ui/react/Accordion';
export default function App() {
const [openMultiple, setOpenMultiple] = React.useState(true);
const [val, setVal] = React.useState(['one']);
+ const [val2, setVal2] = React.useState(['one']);
return (
multiple `Accordion.Section`s can be open at the same time:
@@ -116,6 +117,50 @@ export default function App() {
+
+
+
+
Controlled, at least one section must remain open
+
+
{
+ // console.log(newValue);
+ if (newValue.length > 0) {
+ setVal2(newValue);
+ }
+ }}
+ aria-label="Controlled Accordion, one section must remain open"
+ openMultiple={openMultiple}
+ >
+
+
+ Trigger 1
+
+
+ This is the contents of Accordion.Panel 1, the value is "one"
+
+
+
+
+
+ Trigger 2
+
+
+ This is the contents of Accordion.Panel 2, the value is "two"
+
+
+
+
+
+ Trigger 3
+
+
+ This is the contents of Accordion.Panel 3, the value is "three"
+
+
+
);
@@ -130,14 +175,14 @@ const grey = {
900: '#1C2025',
};
-function useIsDarkMode() {
- const theme = useTheme();
- return theme.palette.mode === 'dark';
-}
+// function useIsDarkMode() {
+// const theme = useTheme();
+// return theme.palette.mode === 'dark';
+// }
function Styles() {
// Replace this with your app logic for determining dark mode
- const isDarkMode = useIsDarkMode();
+ // const isDarkMode = useIsDarkMode();
return (