FlexMenu
FlexMenu is designed to make rendering flex-powered menus from an array of data easy and fast. With flexibility in terms of what you render and ease of styling this menu should cover about 80% of horizontal menu implementations.
FlexMenu
Edit the props to see this component update live!
Data
This component builds a menu (nav > ul > li > a) from an array of data. Each object in the array defines a li item in the menu. To define a li item you must provide a unique "id", a "label" and a "url":
[{id: "1",label: "Comic Books",url: "/comic-books/index",}, ...]
From this object a li item containing an a tag, which uses the "label" and "url", will be added to the menu.
However, sometimes you may want to render a li element in the menu which contains an arbitrary component instead of a standard a tag.
In this case you must add a component property to the data object:
[{id: "1",label: "Comic Books",url: "/comic-books/index",component: "ComicBookComponent"}, ...]
Because you have defined a component you must pass in a componentMap prop to point from the component defined in your data to the component to be used
import { MyComicBookComponent } from "super-comicbook-components"...some stuff<FlexMenucomponentMap={{ComicBookComponent: MyComicBookComponent}}data={[{id: "1",label: "Comic Books",url: "/comic-books/index",component: "ComicBookComponent"}, ...more data]}/>...other stuff
If you want to wrap the component in a link it is important to use the FlexMenuLink component not Link component.
The point and power of FlexMenu lies in the application of functions to provide the correct padding, margins, etc... to render various flex-powered menus. Using the FlexMenuLink component when you want to render a component wrapped in an a tag ensures that the correct values are applied.
Variants
The variant prop is passed through to the FlexMenuLink component. It defines the style of the links.
Variant: mdx
Variant: ui
Variant: chrome
Variant: primary
Variant: secondary
Variant: black
Variant: grey
Variant: white
Variant: info
Variant: success
Variant: warning
Variant: error
Variant: fancy
Props
Justify
The justify prop takes the flex values: "center", "flex-start", "flex-end", "space-between", "space-around".
Add padding to the links if necessary.
justify right
<Box color="primaryText" bg="primary"><FlexMenuvariant="primary"justify="flex-end"height="80px"data={menuData}componentMap={{SiteName: (props) => {return (<SiteBrandingvariant="primary"siteName="SmerthTheme"siteSlogan="Nice building blocks"size="xs"item={{ url: "/" }}><SiteLogo /></SiteBranding>)},}}sx={{li: {borderRight: (theme) => `1px solid ${theme.colors.primaryMuted}`,"&:first-of-type": {borderLeft: (theme) => `1px solid ${theme.colors.primaryMuted}`,},".active": { textDecoration: "none" },"&:hover": { bg: "primaryMuted" },a: {px: [1, 2],},},}}/></Box>
Expand
When passing "center" or "space-around" to the justify prop the menu items are spaced evenly, the distance between each item is the same.
Example: justify space-around
<Box color="secondaryText" bg="secondary"><FlexMenuvariant="secondary"justify="space-around"height="80px"data={menuData}componentMap={{SiteName: (props) => {return (<SiteBrandingvariant="secondary"siteName="SmerthTheme"siteSlogan="Nice building blocks"hideNamehideSloganitem={{ url: "/" }}><SiteLogo /></SiteBranding>)},}}sx={{li: {".active": { textDecoration: "none" },a: {border: "1px solid",borderColor: "secondaryMuted","&:hover": { bg: "secondaryMuted" },},},}}/></Box>
To cause the a tags fill the space between each item you can pass in the expand prop.
This is necessary for some types of styling.
Example: justify space-around with expand prop
<Box color="secondaryText" bg="secondary"><FlexMenuvariant="secondary"justify="space-around"height="80px"expanddata={menuData}componentMap={{SiteName: (props) => {return (<SiteBrandingvariant="secondary"siteName="SmerthTheme"siteSlogan="Nice building blocks"hideNamehideSloganitem={{ url: "/" }}><SiteLogo /></SiteBranding>)},}}sx={{li: {".active": { textDecoration: "none" },a: {border: "1px solid",borderColor: "secondaryMuted","&:hover": { bg: "secondaryMuted" },},},}}/></Box>
wrapOnMobile
By default is set to overflow: hidden on the nav element. If the ul width exceeds the nav the overflow content will not be accessible.
Passing the wrapOnMobile prop does the following:
- sets
overflow: scrollon theulfor desktop screens, so users can scroll through overflow menu items - sets
flex-wrap: wrapon theulon mobile so the list wraps across multiple rows. - set gap for rows to add space between the wrapped content rows.
Example: wrapOnMobile
<Box color="chromeText" bg="chrome" sx={{ position: "relative" }}><FlexMenuvariant="chrome"justify="space-between"height="45px"wrapOnMobilegap="8px 0px"mr={["0px", "0px", "30px"]}data={bigMenuData}componentMap={{SiteName: (props) => {return (<SiteBrandingvariant="chrome"siteName="SmerthTheme"siteSlogan="Nice building blocks"hideNamehideSloganitem={{ url: "/" }}><SiteLogo size="43px" /></SiteBranding>)},}}sx={{li: {".active": { textDecoration: "none" },a: {px: 2,border: "1px solid",borderColor: "chromeMuted","&:hover": { bg: "chromeMuted" },},},}}/><SwapOnMobilemobileComponent={""}desktopComponent={<Boxvariant="layout.svg"px={3}bg="chromeMuted"sx={{ position: "absolute", height: "100%", top: "0px", right: "0px" }}><MdArrowForwardIos /></Box>}/></Box>
Styling Notes
- No background color is set on the menu. It will inherit from the containing element. To have Link colors match the background-color set the menu variant to same color as the container background-color.
- It is often more flexible, for styling purposes, to apply height to the
atag instead of thenavtag, theultag or thelitag. The height of a menu can be set on theatag using the dedicated variable: "header". This can be convenient if you need other page elements (like page offset from top) use the same variable. - You can use the Theme-ui
sxprop to style nested elements in the menu. - When items are justified left, right or centered, apply margin or padding to the
lielement to separate items according to the styling requirements.