VerticalNavbar

A vertical navbar is a good option for more complex sites that have a lot of navigation items they want to display. See Nielsen Norman Group's blog post for more information.

Note: If you're using this component you'll probably want to structure your layout in a manner similar to this:

<section className="sm:flex">
  <VerticalNavbar route={location.pathname} />
  <Container className="grow pb-8">
    {children}
  </Container>
</section>

Note: This component doesn't work well with Footer. You probably won't want to combine the two though.

Source code
import { 
  VerticalNavbar,
  VerticalNavbarTop,
  VerticalNavbarBottom,
  VerticalNavbarSection,
  VerticalNavbarItem,
  VerticalNavbarDropdown
} from "rfui-package";

#Basic

<VerticalNavbar>
  <VerticalNavbarTop>
    <VerticalNavbarItem href="/one" isActive={false}>
      One
    </VerticalNavbarItem>
    <VerticalNavbarItem href="/two" isActive={false}>
      Two
    </VerticalNavbarItem>
    <VerticalNavbarItem href="/three" isActive={false}>
      Three
    </VerticalNavbarItem>
  </VerticalNavbarTop>
</VerticalNavbar>

Set isActive to true if the link is for the URL that the user is currently on. Doing so will give some more visual weight to the element and disable the link. In practice you'll probably end up having something like this:

isActive={route === "/one"}
<VerticalNavbar>
  <VerticalNavbarTop>
    <VerticalNavbarItem href="/one" isActive={true}>
      One
    </VerticalNavbarItem>
    <VerticalNavbarItem href="/two" isActive={false}>
      Two
    </VerticalNavbarItem>
    <VerticalNavbarItem href="/three" isActive={false}>
      Three
    </VerticalNavbarItem>
  </VerticalNavbarTop>
</VerticalNavbar>
If you pass onClick without passing href the navbar item won't be rendered as an <a> tag and will call onClick when clicked.
<VerticalNavbar className="min-h-[300px]!">
  <VerticalNavbarTop>
    <VerticalNavbarItem href="/one" isActive={false}>
      One
    </VerticalNavbarItem>
    <VerticalNavbarItem href="/two" isActive={false}>
      Two
    </VerticalNavbarItem>
    <VerticalNavbarItem href="/three" isActive={false}>
      Three
    </VerticalNavbarItem>
    <VerticalNavbarItem
      type="button"
      onClick={() => {
        alert("Clicked");
      }}
    >
      Click me
    </VerticalNavbarItem>
  </VerticalNavbarTop>
</VerticalNavbar>

#Form button

If you pass formProps without passing href the navbar item will be rendered as something like:

<form {...formProps}>
  <button>{children}</button>
</form>

rather than an <a> tag. This is useful for things like log out functionality, where it is generally desirable to use POST instead of GET.

<VerticalNavbar className="min-h-[300px]!">
  <VerticalNavbarTop>
    <VerticalNavbarItem href="/one" isActive={false}>
      One
    </VerticalNavbarItem>
    <VerticalNavbarItem href="/two" isActive={false}>
      Two
    </VerticalNavbarItem>
    <VerticalNavbarItem href="/three" isActive={false}>
      Three
    </VerticalNavbarItem>
    <VerticalNavbarItem type="form" formProps={{ method: "post" }}>
      Log out
    </VerticalNavbarItem>
  </VerticalNavbarTop>
</VerticalNavbar>

#Sections

<VerticalNavbar>
  <VerticalNavbarTop>
    <VerticalNavbarSection>
      <VerticalNavbarItem href="/one" isActive={false}>
        One
      </VerticalNavbarItem>
      <VerticalNavbarItem href="/two" isActive={false}>
        Two
      </VerticalNavbarItem>
    </VerticalNavbarSection>
    <VerticalNavbarSection>
      <VerticalNavbarItem href="/three" isActive={false}>
        Three
      </VerticalNavbarItem>
      <VerticalNavbarItem href="/four" isActive={false}>
        Four
      </VerticalNavbarItem>
    </VerticalNavbarSection>
  </VerticalNavbarTop>
</VerticalNavbar>

#Heading

<VerticalNavbar>
  <VerticalNavbarTop>
    <VerticalNavbarSection heading="Heading">
      <VerticalNavbarItem href="/one" isActive={false}>
        One
      </VerticalNavbarItem>
      <VerticalNavbarItem href="/two" isActive={false}>
        Two
      </VerticalNavbarItem>
      <VerticalNavbarItem href="/three" isActive={false}>
        Three
      </VerticalNavbarItem>
    </VerticalNavbarSection>
  </VerticalNavbarTop>
</VerticalNavbar>

#Top and bottom

Note: There is a hasMarginUnderneath property that comes in handy if you need to use a VerticalNavbarSection inside of a VerticalNavbarBottom component.
<VerticalNavbar>
  <VerticalNavbarTop>
    <VerticalNavbarItem href="/one" isActive={false}>
      One
    </VerticalNavbarItem>
    <VerticalNavbarItem href="/two" isActive={false}>
      Two
    </VerticalNavbarItem>
  </VerticalNavbarTop>
  <VerticalNavbarBottom>
    <VerticalNavbarItem href="/three" isActive={false}>
      Three
    </VerticalNavbarItem>
    <VerticalNavbarItem href="/four" isActive={false}>
      Four
    </VerticalNavbarItem>
  </VerticalNavbarBottom>
</VerticalNavbar>

#Icons

Note: heroicons is a great resource.

Note: since some icons have more whitespace than others, you might need to use relative positioning to nudge it up or down. Some thing like:

icon={<IconOne className="relative top-1" />}
<VerticalNavbar>
  <VerticalNavbarTop>
    <VerticalNavbarItem href="/one" isActive={false} icon={<IconOne />}>
      One
    </VerticalNavbarItem>
    <VerticalNavbarItem href="/two" isActive={false} icon={<IconTwo />}>
      Two
    </VerticalNavbarItem>
    <VerticalNavbarItem href="/three" isActive={false} icon={<IconThree />}>
      Three
    </VerticalNavbarItem>
  </VerticalNavbarTop>
</VerticalNavbar>

#Dropdown

<VerticalNavbar>
  <VerticalNavbarTop>
    <VerticalNavbarItem href="/one">
      One
    </VerticalNavbarItem>
    <VerticalNavbarItem href="/two">
      Two
    </VerticalNavbarItem>
    <VerticalNavbarDropdown
      title="Dropdown"
      items={[
        { label: "Link", href: "/example" },
        {
          label: "Link (new tab)",
          href: "/example",
          shouldOpenInNewTab: true,
        },
        {
          label: "onClick",
          onClick: () => {
            alert("clicked");
          },
        },
        { label: "Link with icon", href: "/icon", icon: <IconOne /> },
        {
          label: "onClick with icon",
          onClick: () => {
            alert("clicked");
          },
          icon: <IconOne />,
        },
      ]}
    />
  </VerticalNavbarTop>
</VerticalNavbar>

#Props

PropRequiredDefaultType and notes
background-"neutral"
"neutral" | "none"
children-
ComponentChild
...rest--
Omit<ComponentProps<"nav">, "size">
See the docs for rest parameters. For VerticalNavbar, you could pass anything you normally would pass to <nav> because the return value looks something like this:
<nav className={containerClass} {...restWithoutClass}>
  ...
</nav>

VerticalNavbarTop

PropRequiredDefaultType and notes
children-
ComponentChild

VerticalNavbarBottom

PropRequiredDefaultType and notes
children-
ComponentChild

VerticalNavbarSection

PropRequiredDefaultType and notes
heading--
string
hasMarginUnderneath-false
boolean
This property is useful if you need to put a VerticalNavbarSection inside of a VerticalNavbarBottom component.
children-
ComponentChild

VerticalNavbarItem

PropRequiredDefaultType and notes
type-"link"
"link" | "button" | "form"
href--
string
onClick--
() => void
formProps--
ComponentProps<"form">
isActive-
boolean
Set this to be true if this link matches the current URL.
shouldOpenInNewTab-false
boolean
See the docs for the corresponding property in the Link component.
icon--
ComponentChild
A 20x20 icon to be placed to the left of the text.
children-
ComponentChild

VerticalNavbarDropdown

PropRequiredDefaultType and notes
title-
string
items-
DropdownItemType[]