diff --git a/apps/storybook/stories/menubar.stories.module.css b/apps/storybook/stories/menubar.stories.module.css
index a4dc616ea..cf485e533 100644
--- a/apps/storybook/stories/menubar.stories.module.css
+++ b/apps/storybook/stories/menubar.stories.module.css
@@ -4,6 +4,11 @@
padding: 2px;
}
+.rootVertical {
+ display: flex;
+ flex-direction: column;
+}
+
.trigger {
padding: 6px 16px;
border: 0;
diff --git a/apps/storybook/stories/menubar.stories.tsx b/apps/storybook/stories/menubar.stories.tsx
index f68667e28..7901c6d0a 100644
--- a/apps/storybook/stories/menubar.stories.tsx
+++ b/apps/storybook/stories/menubar.stories.tsx
@@ -10,7 +10,10 @@ export default { title: 'Components/Menubar' };
export const Styled = () => {
const [loop, setLoop] = React.useState(false);
const [rtl, setRtl] = React.useState(false);
+ const [vertical, setVertical] = React.useState(false);
const dir = rtl ? 'rtl' : 'ltr';
+ const orientation = vertical ? 'vertical' : 'horizontal';
+ const menubarContentSide = vertical ? 'right' : 'bottom';
const checkOptions = [
'Always Show Bookmarks Bar',
'Always Show Toolbar in Fullscreen',
@@ -49,14 +52,24 @@ export const Styled = () => {
/>
Loop
+
+
-
+
File
-
+
New Tab
New Window
New Incognito Window
@@ -82,7 +95,7 @@ export const Styled = () => {
Edit
-
+
Undo
Redo
@@ -124,7 +137,7 @@ export const Styled = () => {
View
-
+
{checkOptions.map((option) => (
{
Profiles
-
+
{radioOptions.map((option) => (
@@ -176,7 +189,7 @@ export const Styled = () => {
History
-
+
Work
Radix
Github
@@ -197,7 +210,10 @@ export const Styled = () => {
export const Cypress = () => {
const [loop, setLoop] = React.useState(false);
const [rtl, setRtl] = React.useState(false);
+ const [vertical, setVertical] = React.useState(false);
const [portalled, setPortalled] = React.useState(false);
+ const orientation = vertical ? 'vertical' : 'horizontal';
+ const menubarContentSide = vertical ? 'right' : 'bottom';
const dir = rtl ? 'rtl' : 'ltr';
const Portal = portalled ? Menubar.Portal : React.Fragment;
@@ -231,6 +247,15 @@ export const Cypress = () => {
Loop
+
+
-
+
File
-
+
New Tab
New Window
New Incognito Window
@@ -269,7 +295,7 @@ export const Cypress = () => {
Edit
-
+
Undo
@@ -336,7 +362,7 @@ export const Cypress = () => {
History
-
+
Radix
Github
WorkOS
diff --git a/packages/react/menubar/CHANGELOG.md b/packages/react/menubar/CHANGELOG.md
index da0e6fa85..ccb15e8b6 100644
--- a/packages/react/menubar/CHANGELOG.md
+++ b/packages/react/menubar/CHANGELOG.md
@@ -1,5 +1,9 @@
# @radix-ui/react-menubar
+## 1.1.17
+
+- Support new property `orientation (vertical | horizontal)` in `Menubar.Root`
+
## 1.1.16
- Updated dependencies: `@radix-ui/primitive@1.1.3`, `@radix-ui/react-context@1.1.3`, `@radix-ui/react-menu@2.1.16`, `@radix-ui/react-collection@1.1.8`, `@radix-ui/react-primitive@2.1.4`, `@radix-ui/react-roving-focus@1.1.11`
diff --git a/packages/react/menubar/package.json b/packages/react/menubar/package.json
index 7d2996c4e..c8d61184a 100644
--- a/packages/react/menubar/package.json
+++ b/packages/react/menubar/package.json
@@ -1,6 +1,6 @@
{
"name": "@radix-ui/react-menubar",
- "version": "1.1.16",
+ "version": "1.1.17",
"license": "MIT",
"source": "./src/index.ts",
"main": "./src/index.ts",
diff --git a/packages/react/menubar/src/menubar.tsx b/packages/react/menubar/src/menubar.tsx
index 483405eee..6b0ece171 100644
--- a/packages/react/menubar/src/menubar.tsx
+++ b/packages/react/menubar/src/menubar.tsx
@@ -14,6 +14,7 @@ import { useControllableState } from '@radix-ui/react-use-controllable-state';
import type { Scope } from '@radix-ui/react-context';
+type Orientation = 'vertical' | 'horizontal';
type Direction = 'ltr' | 'rtl';
/* -------------------------------------------------------------------------------------------------
@@ -41,6 +42,7 @@ type MenubarContextValue = {
value: string;
dir: Direction;
loop: boolean;
+ orientation: Orientation;
onMenuOpen(value: string): void;
onMenuClose(): void;
onMenuToggle(value: string): void;
@@ -57,6 +59,7 @@ interface MenubarProps extends PrimitiveDivProps {
defaultValue?: string;
onValueChange?: (value: string) => void;
loop?: RovingFocusGroupProps['loop'];
+ orientation?: Orientation;
dir?: RovingFocusGroupProps['dir'];
}
@@ -68,6 +71,7 @@ const Menubar = React.forwardRef(
onValueChange,
defaultValue,
loop = true,
+ orientation = 'horizontal',
dir,
...menubarProps
} = props;
@@ -108,13 +112,14 @@ const Menubar = React.forwardRef(
)}
dir={direction}
loop={loop}
+ orientation={orientation}
>
{
if (disabled) return;
if (['Enter', ' '].includes(event.key)) context.onMenuToggle(menuContext.value);
- if (event.key === 'ArrowDown') context.onMenuOpen(menuContext.value);
+ if (event.key === (context.orientation === 'vertical' ? 'ArrowRight' : 'ArrowDown')) context.onMenuOpen(menuContext.value);
// prevent keydown from scrolling window / first focused item to execute
// that keydown (inadvertently closing the menu)
- if (['Enter', ' ', 'ArrowDown'].includes(event.key)) {
+ if (['Enter', ' ', context.orientation === 'vertical' ? 'ArrowRight' : 'ArrowDown'].includes(event.key)) {
menuContext.wasKeyboardTriggerOpenRef.current = true;
event.preventDefault();
}
@@ -349,7 +354,8 @@ const MenubarContent = React.forwardRef {
- if (['ArrowRight', 'ArrowLeft'].includes(event.key)) {
+ // Prevent navigation when orientation is vertical and menubar content is triggered.
+ if (context.orientation !== 'vertical' && ['ArrowRight', 'ArrowLeft'].includes(event.key)) {
const target = event.target as HTMLElement;
const targetIsSubTrigger = target.hasAttribute('data-radix-menubar-subtrigger');
const isKeyDownInsideSubMenu =