← All proposals

Menu Button

Starting point for a MenuButton proposal.

Extends a PDS componentOpen in Storybook

proposals/MenuButton/NavAccordion.tsx72 lines · View on GitHub
import { ReactNode, useState } from 'react';

import { Icon } from '@pantheon-systems/pds-toolkit-react';

import { mergeClasses } from '../Button/utils';

import './nav-accordion.css';

interface NavAccordionProps {
	/**
	 * Expandable content shown when open.
	 */
	children: ReactNode;
	/**
	 * Additional class names.
	 */
	className?: string;
	/**
	 * Disables the toggle button.
	 */
	disabled?: boolean;
	/**
	 * Content of the toggle button — any ReactNode.
	 */
	label: ReactNode;
}

/**
 * Internal accordion component for the mobile navbar panel.
 * Renders a toggle button with a rotating chevron and expandable content.
 * Used by MenuButton, UserMenu, and WorkspaceSelector.
 */
export const NavAccordion = ({
	children,
	className,
	disabled,
	label,
}: NavAccordionProps) => {
	const [isOpen, setIsOpen] = useState(false);
	const baseClass = 'pds-nav-accordion';

	return (
		<div className={mergeClasses([baseClass, className ?? ''])}>
			<button
				aria-expanded={isOpen}
				className={mergeClasses([
					`${baseClass}__toggle`,
					isOpen ? `${baseClass}__toggle--expanded` : null,
				])}
				disabled={disabled}
				onClick={() => setIsOpen((prev) => !prev)}
				type='button'
			>
				{label}
				<Icon
					className={`${baseClass}__toggle-icon`}
					iconName='angleDown'
					size='m'
				/>
			</button>
			<div
				className={mergeClasses([
					`${baseClass}__content`,
					isOpen ? `${baseClass}__content--expanded` : null,
				])}
			>
				{children}
			</div>
		</div>
	);
};