diff --git a/docs/src/app/new/(content)/components/accordion/demos/hero/css-modules/index.module.css b/docs/src/app/new/(content)/components/accordion/demos/hero/css-modules/index.module.css
new file mode 100644
index 0000000000..10aef9b783
--- /dev/null
+++ b/docs/src/app/new/(content)/components/accordion/demos/hero/css-modules/index.module.css
@@ -0,0 +1,71 @@
+.Root {
+ box-sizing: border-box;
+ display: flex;
+ min-height: 12rem;
+ width: 24rem;
+ max-width: calc(100vw - 8rem);
+ flex-direction: column;
+ justify-content: center;
+}
+
+.Item {
+ border-bottom: 1px solid var(--color-gray-200);
+}
+
+.Header {
+ margin: 0;
+}
+
+.Trigger {
+ box-sizing: border-box;
+ display: flex;
+ width: 100%;
+ align-items: baseline;
+ justify-content: space-between;
+ padding: 0.5rem 0;
+ font: inherit;
+ font-weight: 500;
+ font-size: 1rem;
+ line-height: 1.5rem;
+ letter-spacing: 0em;
+ background: none;
+ border: none;
+ outline: none;
+ cursor: pointer;
+
+ &:focus-visible {
+ outline: 2px solid var(--color-blue);
+ }
+}
+
+.TriggerIcon {
+ box-sizing: border-box;
+ width: 0.75rem;
+ height: 0.75rem;
+ margin-right: 0.5rem;
+ transition: transform 150ms ease-out;
+
+ [data-panel-open] > & {
+ transform: rotate(45deg) scale(1.1);
+ }
+}
+
+.Panel {
+ box-sizing: border-box;
+ height: var(--accordion-panel-height);
+ overflow: hidden;
+ color: var(--color-gray-600);
+ font-size: 0.9375rem;
+ line-height: 1.375rem;
+ letter-spacing: 0.001em;
+ transition: height 150ms ease-out;
+
+ &[data-entering],
+ &[data-exiting] {
+ height: 0;
+ }
+}
+
+.Content {
+ padding-bottom: 0.5rem;
+}
diff --git a/docs/src/app/new/(content)/components/accordion/demos/hero/css-modules/index.tsx b/docs/src/app/new/(content)/components/accordion/demos/hero/css-modules/index.tsx
new file mode 100644
index 0000000000..4ed5cfaafd
--- /dev/null
+++ b/docs/src/app/new/(content)/components/accordion/demos/hero/css-modules/index.tsx
@@ -0,0 +1,61 @@
+import * as React from 'react';
+import { Accordion } from '@base-ui-components/react/accordion';
+import styles from './index.module.css';
+
+export default function ExampleAccordion() {
+ return (
+
+
+
+
+ What is Base UI?
+
+
+
+
+
+ Base UI is a library of high-quality, accessible, unstyled React
+ components for design systems and web apps.
+
+
+
+
+
+
+
+ How do I get started?
+
+
+
+
+
+ Head to the “Quick start” guide in the docs. If you’ve used unstyled
+ libraries before, you’ll feel right at home.
+
+
+
+
+
+
+
+ Can I use it for my next project?
+
+
+
+
+
+ Of course! Base UI is free and open source.
+
+
+
+
+ );
+}
+
+function PlusIcon(props: React.ComponentProps<'svg'>) {
+ return (
+
+ );
+}
diff --git a/docs/src/app/new/(content)/components/accordion/demos/hero/index.ts b/docs/src/app/new/(content)/components/accordion/demos/hero/index.ts
new file mode 100644
index 0000000000..80097d6015
--- /dev/null
+++ b/docs/src/app/new/(content)/components/accordion/demos/hero/index.ts
@@ -0,0 +1,3 @@
+'use client';
+export { default as CssModules } from './css-modules';
+export { default as Tailwind } from './tailwind';
diff --git a/docs/src/app/new/(content)/components/accordion/demos/hero/tailwind/index.tsx b/docs/src/app/new/(content)/components/accordion/demos/hero/tailwind/index.tsx
new file mode 100644
index 0000000000..f9d03b6dd1
--- /dev/null
+++ b/docs/src/app/new/(content)/components/accordion/demos/hero/tailwind/index.tsx
@@ -0,0 +1,58 @@
+import * as React from 'react';
+import { Accordion } from '@base-ui-components/react/accordion';
+
+export default function ExampleAccordion() {
+ return (
+
+
+
+
+ What is Base UI?
+
+
+
+
+
+ Base UI is a library of high-quality, accessible, unstyled React
+ components for design systems and web apps.
+
+
+
+
+
+
+
+ How do I get started?
+
+
+
+
+
+ Head to the “Quick start” guide in the docs. If you’ve used unstyled
+ libraries before, you’ll feel right at home.
+
+
+
+
+
+
+
+ Can I use it for my next project?
+
+
+
+
+ Of course! Base UI is free and open source.
+
+
+
+ );
+}
+
+function PlusIcon(props: React.ComponentProps<'svg'>) {
+ return (
+
+ );
+}
diff --git a/docs/src/app/new/(content)/components/accordion/page.mdx b/docs/src/app/new/(content)/components/accordion/page.mdx
new file mode 100644
index 0000000000..aec5846767
--- /dev/null
+++ b/docs/src/app/new/(content)/components/accordion/page.mdx
@@ -0,0 +1,25 @@
+# Accordion
+
+A set of collapsible panels with headings.
+
+
+
+
+## API reference
+
+Import the component and place its parts the following way:
+
+```jsx title="Anatomy"
+import { Accordion } from '@base-ui-components/react/accordion';
+
+
+
+
+
+
+
+
+;
+```
+
+
diff --git a/docs/src/app/new/(content)/components/alert-dialog/demos/hero/css-modules/index.module.css b/docs/src/app/new/(content)/components/alert-dialog/demos/hero/css-modules/index.module.css
new file mode 100644
index 0000000000..91f4db5eb1
--- /dev/null
+++ b/docs/src/app/new/(content)/components/alert-dialog/demos/hero/css-modules/index.module.css
@@ -0,0 +1,93 @@
+.Button {
+ box-sizing: border-box;
+ display: flex;
+ padding: 0.5rem 0.875rem;
+ margin: 0;
+ border: none;
+ border-radius: 0.375rem;
+ background-color: var(--color-gray-50);
+ font: inherit;
+ font-weight: 500;
+ color: var(--color-gray-900);
+ outline: 1px solid var(--color-gray-200);
+ user-select: none;
+
+ &[data-color='red'] {
+ color: var(--color-red);
+ }
+
+ @media (hover: hover) {
+ &:hover {
+ background-color: var(--color-gray-100);
+ }
+ }
+
+ &:focus-visible {
+ outline: 2px solid var(--color-blue);
+ }
+
+ &:active {
+ background-color: var(--color-gray-100);
+ }
+}
+
+.Backdrop {
+ position: fixed;
+ inset: 0;
+ background-color: black;
+ opacity: 0.2;
+ transition: opacity 150ms;
+
+ @media (prefers-color-scheme: dark) {
+ opacity: 0.7;
+ }
+
+ &[data-entering],
+ &[data-exiting] {
+ opacity: 0;
+ }
+}
+
+.Popup {
+ box-sizing: border-box;
+ position: fixed;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ width: 24rem;
+ max-width: calc(100vw - 3rem);
+ margin-top: -2rem;
+ padding: 1.5rem;
+ border-radius: 0.5rem;
+ border: 1px solid var(--color-gray-300);
+ background-color: var(--color-gray-50);
+ color: var(--color-gray-950);
+ outline: 0;
+ transition: all 150ms;
+
+ &[data-entering],
+ &[data-exiting] {
+ opacity: 0;
+ transform: translate(-50%, -50%) scale(0.9);
+ }
+}
+
+.Title {
+ margin-top: -0.375rem;
+ margin-bottom: 0.25rem;
+ font-size: 1.125rem;
+ line-height: 1.75rem;
+ letter-spacing: -0.0025em;
+ font-weight: 500;
+}
+
+.Description {
+ margin: 0 0 1.5rem;
+ color: var(--color-gray-600);
+}
+
+.Actions {
+ display: flex;
+ justify-content: flex-end;
+ gap: 1rem;
+}
diff --git a/docs/src/app/new/(content)/components/alert-dialog/demos/hero/css-modules/index.tsx b/docs/src/app/new/(content)/components/alert-dialog/demos/hero/css-modules/index.tsx
new file mode 100644
index 0000000000..67e7fca52f
--- /dev/null
+++ b/docs/src/app/new/(content)/components/alert-dialog/demos/hero/css-modules/index.tsx
@@ -0,0 +1,28 @@
+import * as React from 'react';
+import { AlertDialog } from '@base-ui-components/react/alert-dialog';
+import styles from './index.module.css';
+
+export default function ExampleAlertDialog() {
+ return (
+
+
+ Discard draft
+
+
+
+
+ Discard draft?
+
+
+ You can't undo this action.
+
+
+
+
+ );
+}
diff --git a/docs/src/app/new/(content)/components/alert-dialog/demos/hero/index.ts b/docs/src/app/new/(content)/components/alert-dialog/demos/hero/index.ts
new file mode 100644
index 0000000000..80097d6015
--- /dev/null
+++ b/docs/src/app/new/(content)/components/alert-dialog/demos/hero/index.ts
@@ -0,0 +1,3 @@
+'use client';
+export { default as CssModules } from './css-modules';
+export { default as Tailwind } from './tailwind';
diff --git a/docs/src/app/new/(content)/components/alert-dialog/demos/hero/tailwind/index.tsx b/docs/src/app/new/(content)/components/alert-dialog/demos/hero/tailwind/index.tsx
new file mode 100644
index 0000000000..46aa816b02
--- /dev/null
+++ b/docs/src/app/new/(content)/components/alert-dialog/demos/hero/tailwind/index.tsx
@@ -0,0 +1,29 @@
+import * as React from 'react';
+import { AlertDialog } from '@base-ui-components/react/alert-dialog';
+
+export default function ExampleAlertDialog() {
+ return (
+
+
+ Discard draft
+
+
+
+
+ Discard draft?
+
+
+ You can’t undo this action.
+
+
+
+ Cancel
+
+
+ Discard
+
+
+
+
+ );
+}
diff --git a/docs/src/app/new/(content)/components/alert-dialog/page.mdx b/docs/src/app/new/(content)/components/alert-dialog/page.mdx
new file mode 100644
index 0000000000..87620deac8
--- /dev/null
+++ b/docs/src/app/new/(content)/components/alert-dialog/page.mdx
@@ -0,0 +1,26 @@
+# Alert Dialog
+
+A dialog that requires user response to proceed.
+
+
+
+
+## API reference
+
+Import the component and place its parts the following way:
+
+```jsx title="Anatomy"
+import { AlertDialog } from '@base-ui-components/react/alert-dialog';
+
+
+
+
+
+
+
+
+
+;
+```
+
+
diff --git a/docs/src/app/new/(content)/components/checkbox-group/demos/hero/css-modules/index.module.css b/docs/src/app/new/(content)/components/checkbox-group/demos/hero/css-modules/index.module.css
new file mode 100644
index 0000000000..67dd06d4e1
--- /dev/null
+++ b/docs/src/app/new/(content)/components/checkbox-group/demos/hero/css-modules/index.module.css
@@ -0,0 +1,58 @@
+.Group {
+ display: flex;
+ flex-direction: column;
+ gap: 0.25rem;
+}
+
+.Label {
+ font-weight: 500;
+}
+
+.Item {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+}
+
+.Checkbox {
+ box-sizing: border-box;
+ display: flex;
+ width: 1.25rem;
+ height: 1.25rem;
+ align-items: center;
+ justify-content: center;
+ border-radius: 0.25rem;
+ outline: 0;
+ padding: 0;
+ margin: 0;
+ border: none;
+
+ &[data-checked] {
+ background-color: var(--color-gray-900);
+ }
+
+ &[data-unchecked] {
+ border: 1px solid var(--color-gray-300);
+ background-color: transparent;
+ }
+
+ &:focus-visible {
+ outline: 2px solid var(--color-blue);
+ outline-offset: 2px;
+ }
+}
+
+.Indicator {
+ width: 0.75rem;
+ height: 0.75rem;
+ color: var(--color-gray-50);
+
+ &[data-unchecked] {
+ display: none;
+ }
+}
+
+.Icon {
+ width: 100%;
+ height: 100%;
+}
diff --git a/docs/src/app/new/(content)/components/checkbox-group/demos/hero/css-modules/index.tsx b/docs/src/app/new/(content)/components/checkbox-group/demos/hero/css-modules/index.tsx
new file mode 100644
index 0000000000..7f3333e3d6
--- /dev/null
+++ b/docs/src/app/new/(content)/components/checkbox-group/demos/hero/css-modules/index.tsx
@@ -0,0 +1,57 @@
+import * as React from 'react';
+import { Checkbox } from '@base-ui-components/react/checkbox';
+import { CheckboxGroup } from '@base-ui-components/react/checkbox-group';
+import styles from './index.module.css';
+
+export default function ExampleCheckboxGroup() {
+ return (
+
+
+ Apples
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+function CheckIcon(props: React.ComponentProps<'svg'>) {
+ return (
+
+ );
+}
diff --git a/docs/src/app/new/(content)/components/checkbox-group/demos/hero/index.ts b/docs/src/app/new/(content)/components/checkbox-group/demos/hero/index.ts
new file mode 100644
index 0000000000..80097d6015
--- /dev/null
+++ b/docs/src/app/new/(content)/components/checkbox-group/demos/hero/index.ts
@@ -0,0 +1,3 @@
+'use client';
+export { default as CssModules } from './css-modules';
+export { default as Tailwind } from './tailwind';
diff --git a/docs/src/app/new/(content)/components/checkbox-group/demos/hero/tailwind/index.tsx b/docs/src/app/new/(content)/components/checkbox-group/demos/hero/tailwind/index.tsx
new file mode 100644
index 0000000000..15150b0658
--- /dev/null
+++ b/docs/src/app/new/(content)/components/checkbox-group/demos/hero/tailwind/index.tsx
@@ -0,0 +1,64 @@
+import * as React from 'react';
+import { Checkbox } from '@base-ui-components/react/checkbox';
+import { CheckboxGroup } from '@base-ui-components/react/checkbox-group';
+
+export default function ExampleCheckboxGroup() {
+ return (
+
+
+ Apples
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+function CheckIcon(props: React.ComponentProps<'svg'>) {
+ return (
+
+ );
+}
diff --git a/docs/src/app/new/(content)/components/checkbox-group/page.mdx b/docs/src/app/new/(content)/components/checkbox-group/page.mdx
new file mode 100644
index 0000000000..3c5b4e1097
--- /dev/null
+++ b/docs/src/app/new/(content)/components/checkbox-group/page.mdx
@@ -0,0 +1,21 @@
+# Checkbox Group
+
+A series of checkboxes with a shared state.
+
+
+
+
+## API reference
+
+Checkbox Group is meant to be composed together with Checkbox. Import the components and place them together:
+
+```jsx title="Anatomy"
+import { Checkbox } from '@base-ui-components/react/checkbox';
+import { CheckboxGroup } from '@base-ui-components/react/checkbox-group';
+
+
+
+;
+```
+
+
diff --git a/docs/src/app/new/(content)/components/checkbox/demos/hero/css-modules/index.module.css b/docs/src/app/new/(content)/components/checkbox/demos/hero/css-modules/index.module.css
new file mode 100644
index 0000000000..337c01a41a
--- /dev/null
+++ b/docs/src/app/new/(content)/components/checkbox/demos/hero/css-modules/index.module.css
@@ -0,0 +1,42 @@
+.Checkbox {
+ box-sizing: border-box;
+ display: flex;
+ width: 1.25rem;
+ height: 1.25rem;
+ align-items: center;
+ justify-content: center;
+ border-radius: 0.25rem;
+ outline: 0;
+ padding: 0;
+ margin: 0;
+ border: none;
+
+ &[data-checked] {
+ background-color: var(--color-gray-900);
+ }
+
+ &[data-unchecked] {
+ border: 1px solid var(--color-gray-300);
+ background-color: transparent;
+ }
+
+ &:focus-visible {
+ outline: 2px solid var(--color-blue);
+ outline-offset: 2px;
+ }
+}
+
+.Indicator {
+ width: 0.75rem;
+ height: 0.75rem;
+ color: var(--color-gray-50);
+
+ &[data-unchecked] {
+ display: none;
+ }
+}
+
+.Icon {
+ width: 100%;
+ height: 100%;
+}
diff --git a/docs/src/app/new/(content)/components/checkbox/demos/hero/css-modules/index.tsx b/docs/src/app/new/(content)/components/checkbox/demos/hero/css-modules/index.tsx
new file mode 100644
index 0000000000..be6c7bc9dd
--- /dev/null
+++ b/docs/src/app/new/(content)/components/checkbox/demos/hero/css-modules/index.tsx
@@ -0,0 +1,21 @@
+import * as React from 'react';
+import { Checkbox } from '@base-ui-components/react/checkbox';
+import styles from './index.module.css';
+
+export default function ExampleCheckbox() {
+ return (
+
+
+
+
+
+ );
+}
+
+function CheckIcon(props: React.ComponentProps<'svg'>) {
+ return (
+
+ );
+}
diff --git a/docs/src/app/new/(content)/components/checkbox/demos/hero/index.ts b/docs/src/app/new/(content)/components/checkbox/demos/hero/index.ts
new file mode 100644
index 0000000000..80097d6015
--- /dev/null
+++ b/docs/src/app/new/(content)/components/checkbox/demos/hero/index.ts
@@ -0,0 +1,3 @@
+'use client';
+export { default as CssModules } from './css-modules';
+export { default as Tailwind } from './tailwind';
diff --git a/docs/src/app/new/(content)/components/checkbox/demos/hero/tailwind/index.tsx b/docs/src/app/new/(content)/components/checkbox/demos/hero/tailwind/index.tsx
new file mode 100644
index 0000000000..e7aeca91f3
--- /dev/null
+++ b/docs/src/app/new/(content)/components/checkbox/demos/hero/tailwind/index.tsx
@@ -0,0 +1,23 @@
+import * as React from 'react';
+import { Checkbox } from '@base-ui-components/react/checkbox';
+
+export default function ExampleCheckbox() {
+ return (
+
+
+
+
+
+ );
+}
+
+function CheckIcon(props: React.ComponentProps<'svg'>) {
+ return (
+
+ );
+}
diff --git a/docs/src/app/new/(content)/components/checkbox/page.mdx b/docs/src/app/new/(content)/components/checkbox/page.mdx
new file mode 100644
index 0000000000..3d367cb2f0
--- /dev/null
+++ b/docs/src/app/new/(content)/components/checkbox/page.mdx
@@ -0,0 +1,20 @@
+# Checkbox
+
+An easily stylable checkbox component.
+
+
+
+
+## API reference
+
+Import the component and place its parts the following way:
+
+```jsx title="Anatomy"
+import { Checkbox } from '@base-ui-components/react/checkbox';
+
+
+
+;
+```
+
+
diff --git a/docs/src/app/new/(content)/components/dialog/demos/hero/css-modules/index.module.css b/docs/src/app/new/(content)/components/dialog/demos/hero/css-modules/index.module.css
index 138eb292f9..bad9b0459f 100644
--- a/docs/src/app/new/(content)/components/dialog/demos/hero/css-modules/index.module.css
+++ b/docs/src/app/new/(content)/components/dialog/demos/hero/css-modules/index.module.css
@@ -1,5 +1,4 @@
-.Trigger,
-.Close {
+.Button {
box-sizing: border-box;
display: flex;
padding: 0.5rem 0.875rem;
@@ -28,12 +27,7 @@
}
}
-.Close {
- margin-left: auto;
-}
-
.Backdrop {
- box-sizing: border-box;
position: fixed;
inset: 0;
background-color: black;
@@ -56,8 +50,8 @@
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
- width: 320px;
- max-width: calc(100vw - 48px);
+ width: 24rem;
+ max-width: calc(100vw - 3rem);
margin-top: -2rem;
padding: 1.5rem;
border-radius: 0.5rem;
@@ -75,7 +69,6 @@
}
.Title {
- box-sizing: border-box;
margin-top: -0.375rem;
margin-bottom: 0.25rem;
font-size: 1.125rem;
@@ -85,7 +78,12 @@
}
.Description {
- box-sizing: border-box;
- margin: 0 0 1rem;
+ margin: 0 0 1.5rem;
color: var(--color-gray-600);
}
+
+.Actions {
+ display: flex;
+ justify-content: flex-end;
+ gap: 1rem;
+}
diff --git a/docs/src/app/new/(content)/components/dialog/demos/hero/css-modules/index.tsx b/docs/src/app/new/(content)/components/dialog/demos/hero/css-modules/index.tsx
index 77351605bb..6f9fdce841 100644
--- a/docs/src/app/new/(content)/components/dialog/demos/hero/css-modules/index.tsx
+++ b/docs/src/app/new/(content)/components/dialog/demos/hero/css-modules/index.tsx
@@ -12,7 +12,9 @@ export default function ExampleDialog() {
You are all caught up. Good job!
- Close
+
+ Close
+
);
diff --git a/docs/src/app/new/(content)/components/dialog/demos/hero/tailwind/index.tsx b/docs/src/app/new/(content)/components/dialog/demos/hero/tailwind/index.tsx
index 0645d4f6f0..8912b5c348 100644
--- a/docs/src/app/new/(content)/components/dialog/demos/hero/tailwind/index.tsx
+++ b/docs/src/app/new/(content)/components/dialog/demos/hero/tailwind/index.tsx
@@ -8,16 +8,18 @@ export default function ExampleDialog() {
View notifications
-
+
Your notifications
-
+
You are all caught up. Good job!
-
- Close
-
+
+
+ Close
+
+
);
diff --git a/docs/src/app/new/(content)/components/dialog/page.mdx b/docs/src/app/new/(content)/components/dialog/page.mdx
index 96656ca9ab..7c770744d9 100644
--- a/docs/src/app/new/(content)/components/dialog/page.mdx
+++ b/docs/src/app/new/(content)/components/dialog/page.mdx
@@ -1,6 +1,7 @@
# Dialog
A popup that opens on top of the entire page.
+
diff --git a/docs/src/mdx-components.tsx b/docs/src/mdx-components.tsx
index b360b8f493..075d76c342 100644
--- a/docs/src/mdx-components.tsx
+++ b/docs/src/mdx-components.tsx
@@ -65,13 +65,14 @@ export const mdxComponents: MDXComponents = {
QuickNav,
AttributesTable: (props) => ,
CssVariablesTable: (props) => ,
+ Meta: (props: React.ComponentProps<'meta'>) => {
+ if (props.name === 'description' && String(props.content).length > 170) {
+ throw new Error('Meta description shouldn’t be longer than 170 chars');
+ }
+ return ;
+ },
PropsTable: (props) => ,
- Subtitle: (props) => (
-
-
-
-
- ),
+ Subtitle: (props) => ,
};
export const inlineMdxComponents: MDXComponents = {
diff --git a/docs/src/nav.ts b/docs/src/nav.ts
index 4aa91f8321..7e815feae9 100644
--- a/docs/src/nav.ts
+++ b/docs/src/nav.ts
@@ -35,15 +35,15 @@ export const nav = [
label: 'Composition',
href: '/new/handbook/composition',
},
- {
- label: 'Migrating from Radix',
- href: '/new/handbook/migrating-from-radix',
- },
],
},
{
label: 'Components',
links: [
+ {
+ label: 'Accordion',
+ href: '/new/components/accordion',
+ },
{
label: 'Alert Dialog',
href: '/new/components/alert-dialog',
@@ -54,7 +54,7 @@ export const nav = [
},
{
label: 'Checkbox Group',
- href: '/new/components/checkbox group',
+ href: '/new/components/checkbox-group',
},
{
label: 'Collapsible',