useExpandableLayout
function useExpandableLayout(
options: ExpandableLayoutOptions
): ExpandableLayoutImplementation;
The useExpandableLayout
layout hook is used to create a layout where
the main navigation can be toggled using a button. The navigation will
always appear in a Sheet
on mobile, but can be rendered inline on
larger viewports.
Example Usage
The useExpandableLayout
hook requires the pathname
to be provided just like
the useTemporaryLayout
hook.
import { AppBarTitle } from "@react-md/core/app-bar/AppBarTitle";
import { Button } from "@react-md/core/button/Button";
import { LayoutAppBar } from "@react-md/core/layout/LayoutAppBar";
import { LayoutNav } from "@react-md/core/layout/LayoutNav";
import { Main } from "@react-md/core/layout/Main";
import { useExpandableLayout } from "@react-md/core/layout/useExpandableLayout";
import { Sheet } from "@react-md/core/sheet/Sheet";
import { type ReactElement, type ReactNode } from "react";
import { CustomNavigation } from "./CustomNavigation";
export interface LayoutProps {
children: ReactNode;
}
export function Layout(props: LayoutProps): ReactElement {
const { children } = props;
// choose whichever one for your app
// nextjs app dir
const pathname = usePathname();
// nextjs pages
const { pathname } = useRouter();
// react router
const { pathname } = useHistory();
const {
temporary,
appBarProps,
expandableNavProps,
mainProps,
navToggleProps,
temporaryNavProps,
windowSplitterProps,
} = useExpandableLayout({ pathname });
return (
<>
<LayoutAppBar {...appBarProps}>
<Button {...navToggleProps} />
<AppBarTitle>Hello, world!</AppBarTitle>
</LayoutAppBar>
<LayoutNav {...expandableNavProps}>
<CustomNavigation />
</LayoutNav>
{temporary && (
<Sheet {...temporaryNavProps}>
<CustomNavigation />
</Sheet>
)}
<Main {...mainProps}>{children}</Main>
</>
);
}
Conditionally Rendering
If you have a large navigation panel, you can conditionally render the
LayoutNav
with the persistent
boolean returned by the hook which will
ensure that the DOM has rehydrated before unmounting to prevent SSR errors.
const {
temporary,
+ persistent,
appBarProps,
expandableNavProps,
mainProps,
navToggleProps,
temporaryNavProps,
windowSplitterProps,
} = useExpandableLayout({ pathname });
return (
<>
<LayoutAppBar {...appBarProps}>
<Button {...navToggleProps} />
<AppBarTitle>Hello, world!</AppBarTitle>
</LayoutAppBar>
- <LayoutNav {...expandableNavProps}>
- <CustomNavigation />
- </LayoutNav>
+ {persistent && (
+ <LayoutNav {...expandableNavProps}>
+ <CustomNavigation />
+ </LayoutNav>
+ )}
{temporary && (
<Sheet {...temporaryNavProps}>
<CustomNavigation />
</Sheet>
)}
<Main {...mainProps}>{children}</Main>
</>
);
Parameters
options
- An object with the following definition:
export interface ExpandableLayoutOptions extends TemporaryLayoutOptions {
/** @defaultValue `"fixed"` */
appBarPosition?: CssPosition;
/** @defaultValue `false` */
defaultExpanded?: UseStateInitializer<boolean>;
/**
* Set this to `true` if the expandable navigation should be the full height
* of the screen. This will also update the app bar so that it is not covered
* by the navigation. The default behavior is to place the navigation below
* the fixed header.
*
* Set this to `"static"` to make the navigation span the full height of the
* screen and hide the button until the screen shrinks to the temporary
* layout type.
*
* @defaultValue `false`
*/
fullHeightNav?: boolean | "static";
/** @see {@link HorizontalLayoutTransitionOptions} */
transitionProps?: Omit<HorizontalLayoutTransitionOptions, "transitionIn">;
/**
* Set this to `"desktop"` if you want to use the temporary navigation until
* the viewport is at least desktop width instead of tablet.
*
* @defaultValue `"tablet"`
*/
temporaryUntil?: "tablet" | "desktop";
}
Returns
export interface ExpandableLayoutImplementation
extends TemporaryLayoutImplementation {
temporary: boolean;
persistent: boolean;
expanded: boolean;
expandNavigation: () => void;
collapseNavigation: () => void;
toggleNavigation: () => void;
appBarProps: ProvidedLayoutAppBarProps;
mainProps: ProvidedLayoutMainProps;
navToggleProps: ProvidedExpandableLayoutNavToggleProps;
expandableNavProps: ProvidedLayoutNavProps;
}
export type ProvidedLayoutAppBarProps = ProvidedTemporaryLayoutAppBarProps &
Partial<CSSTransitionElementProps<HTMLElement>>;
export type ProvidedLayoutNavProps = Pick<
LayoutNavProps,
"expanded" | "appBarOffset"
>;
export interface ProvidedLayoutMainProps
extends ProvidedTemporaryLayoutMainProps,
CSSTransitionElementProps<HTMLElement> {}
export interface ProvidedExpandableLayoutNavToggleProps
extends ProvidedLayoutNavToggleProps {
className: string;
}