Vertical navigation for an app: links, groups and folders in a full-height column that can collapse to an icon rail.
import { Sidebar } from 'frontile';
Sidebar yields its parts. Put Item links in Body, give each an @href
(or a @route) and its label as the block, and mark the current page with
@isActive. The sidebar is as tall as its container.
import { Sidebar } from 'frontile';
<template>
<div class='not-prose h-56'>
<Sidebar as |sidebar|>
<sidebar.Body>
<sidebar.Item @href='#inbox' @isActive={{true}}>Inbox</sidebar.Item>
<sidebar.Item @href='#drafts'>Drafts</sidebar.Item>
<sidebar.Item @href='#sent'>Sent</sidebar.Item>
</sidebar.Body>
</Sidebar>
</div>
</template>
Header, Body and Footer stack top to bottom; Body takes the free
space and scrolls. Header and footer hold your own markup, such as a brand
or an account menu.Item is a link, or a button when it has neither @href nor @route.Group puts a heading over a set of items.Folder is a trigger that opens and closes a set of items.Toggle collapses and expands the sidebar. There is no default toggle:
place it where you want it.Collapse the sidebar with its toggle.
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { on } from '@ember/modifier';
import { Sidebar } from 'frontile';
import {
ViewIcon,
StarIcon,
PackageIcon,
SettingsIcon,
LogoutIcon,
SparklesIcon
} from 'site/components/icons';
export default class SidebarAnatomyExample extends Component {
@tracked signedOut = false;
signOut = () => {
this.signedOut = true;
};
<template>
<div class='demo-stack demo-stack--wide not-prose'>
<div
class='flex h-96 overflow-hidden rounded-lg border border-neutral-soft'
>
<Sidebar
@label='Workspace'
@class='border-e border-neutral-muted'
as |sidebar|
>
<sidebar.Header>
<SparklesIcon class='size-5 shrink-0 text-primary' />
<span class='truncate text-sm font-semibold' data-sidebar-label>
Acme
</span>
<sidebar.Toggle class='ml-auto' />
</sidebar.Header>
<sidebar.Body>
<sidebar.Item
@href='#overview'
@icon={{ViewIcon}}
@isActive={{true}}
>
Overview
</sidebar.Item>
<sidebar.Folder @label='Products' @icon={{PackageIcon}} as |folder|>
<folder.Item @href='#all-products'>All products</folder.Item>
<folder.Item @href='#categories'>Categories</folder.Item>
</sidebar.Folder>
<sidebar.Group @label='Saved'>
<sidebar.Item @href='#starred' @icon={{StarIcon}}>
Starred
</sidebar.Item>
</sidebar.Group>
</sidebar.Body>
<sidebar.Footer>
<sidebar.Item @href='#settings' @icon={{SettingsIcon}}>
Settings
</sidebar.Item>
<sidebar.Item @icon={{LogoutIcon}} {{on 'click' this.signOut}}>
Sign out
</sidebar.Item>
</sidebar.Footer>
</Sidebar>
<p class='flex-1 p-4 text-sm text-neutral-firm'>
{{if
this.signedOut
'Signed out.'
'Collapse the sidebar with its toggle.'
}}
</p>
</div>
</div>
</template>
}
@icon takes an icon component; the label is the block. An item with
@href is a plain anchor; with neither @href nor @route it is a
<button> for your own handler, attached with the on modifier, like
Sign out above.
@isActive marks the current page.@isDisabled dims the item and drops its href, so it cannot be followed.@isHidden renders nothing, for items the current user should not see.import { Sidebar } from 'frontile';
import {
ViewIcon,
StarIcon,
ArchiveIcon,
DeleteIcon
} from 'site/components/icons';
<template>
<div class='not-prose h-56'>
<Sidebar @label='Projects' as |sidebar|>
<sidebar.Body>
<sidebar.Item @href='#all' @icon={{ViewIcon}} @isActive={{true}}>
All projects
</sidebar.Item>
<sidebar.Item @href='#starred' @icon={{StarIcon}}>
Starred
</sidebar.Item>
<sidebar.Item
@href='#archived'
@icon={{ArchiveIcon}}
@isDisabled={{true}}
>
Archived
</sidebar.Item>
<sidebar.Item @href='#purge' @icon={{DeleteIcon}} @isHidden={{true}}>
Purge data
</sidebar.Item>
</sidebar.Body>
</Sidebar>
</div>
</template>
An item's element is an <a>, a <button>, or an <li> row inside a
collapsed folder's menu, so attributes you pass to it must suit all three.
@badge shows a count or short status at the end of the row. In the collapsed
rail, where only the icon shows, it moves onto the icon's corner. 0, null,
undefined and '' show nothing. Screen readers hear the badge after the
label; @badgeLabel words it, such as "3 unread".
import { Sidebar } from 'frontile';
import { BookIcon, UserIcon } from 'site/components/icons';
<template>
<div class='not-prose h-40'>
<Sidebar @label='Inbox' as |sidebar|>
<sidebar.Body>
<sidebar.Item
@href='#messages'
@icon={{BookIcon}}
@badge={{3}}
@badgeLabel='3 unread'
>
Messages
</sidebar.Item>
<sidebar.Item @href='#requests' @badge='New'>
Access requests
</sidebar.Item>
<sidebar.Item @href='#members' @icon={{UserIcon}}>
Members
</sidebar.Item>
</sidebar.Body>
</Sidebar>
</div>
</template>
With @route (plus @model, @models or @query as needed) an item renders
a LinkTo, and the router decides whether it is active. A parent route counts
as active on its child routes, so @route='users' stays active on
users.show. @isActive always wins over the router; pass it when only an
exact match should light up.
<sidebar.Item @route='dashboard' @icon={{ViewIcon}}>Dashboard</sidebar.Item>
<sidebar.Item @route='users.show' @model={{@currentUser.id}} @icon={{UserIcon}}>
My profile
</sidebar.Item>
Group puts a heading over a set of items and names the set after it with
@label.
import { Sidebar } from 'frontile';
import {
ViewIcon,
StarIcon,
UserIcon,
SettingsIcon
} from 'site/components/icons';
<template>
<div class='not-prose h-72'>
<Sidebar as |sidebar|>
<sidebar.Body>
<sidebar.Group @label='Projects'>
<sidebar.Item @href='#all' @icon={{ViewIcon}} @isActive={{true}}>
All projects
</sidebar.Item>
<sidebar.Item @href='#starred' @icon={{StarIcon}}>
Starred
</sidebar.Item>
</sidebar.Group>
<sidebar.Group @label='Admin'>
<sidebar.Item @href='#members' @icon={{UserIcon}}>
Members
</sidebar.Item>
<sidebar.Item @href='#settings' @icon={{SettingsIcon}}>
Settings
</sidebar.Item>
</sidebar.Group>
</sidebar.Body>
</Sidebar>
</div>
</template>
Folder opens and closes a set of items, one level deep. Give it a @label,
an optional @icon, and write its items as folder.Item.
A folder holding the current page opens by itself, on load and whenever one of
its items becomes the current page, but never reopens after the user closes
it. @defaultOpen sets the starting state otherwise. To control it, pass
@open and update it from @onOpenChange, which is also called for the
automatic open.
The trigger is not styled active, since the item inside is the current page,
but it carries data-active="true" for your own styles. A folder with no
visible items is hidden, so a section the user may not see leaves no empty row.
import { Sidebar } from 'frontile';
import { PackageIcon, BookIcon } from 'site/components/icons';
<template>
<div class='not-prose h-64'>
<Sidebar @label='Catalog' as |sidebar|>
<sidebar.Body>
<sidebar.Folder @label='Products' @icon={{PackageIcon}} as |folder|>
<folder.Item @href='#all-products' @isActive={{true}}>
All products
</folder.Item>
<folder.Item @href='#categories'>Categories</folder.Item>
</sidebar.Folder>
<sidebar.Folder @label='Reports' @icon={{BookIcon}} as |folder|>
<folder.Item @href='#sales'>Sales</folder.Item>
<folder.Item @href='#inventory'>Inventory</folder.Item>
</sidebar.Folder>
</sidebar.Body>
</Sidebar>
</div>
</template>
Toggle collapses the sidebar to an icon rail and expands it again. In the
rail:
folder.Item in a folder's block: anything else renders
twice in the rail.<span data-sidebar-label>, which hides it the same way.Collapse this sidebar, then hover the icons and open the folder.
Page content
import { Sidebar } from 'frontile';
import {
ViewIcon,
PackageIcon,
StarIcon,
SparklesIcon
} from 'site/components/icons';
<template>
<div class='demo-stack demo-stack--wide not-prose'>
<div
class='flex h-80 overflow-hidden rounded-lg border border-neutral-soft'
>
<Sidebar
@label='Workspace'
@class='border-e border-neutral-muted'
as |sidebar|
>
<sidebar.Header>
<SparklesIcon class='size-5 shrink-0 text-primary' />
<span class='truncate text-sm font-semibold' data-sidebar-label>
Acme
</span>
<sidebar.Toggle class='ml-auto' />
</sidebar.Header>
<sidebar.Body>
<sidebar.Item @href='#overview' @icon={{ViewIcon}} @isActive={{true}}>
Overview
</sidebar.Item>
<sidebar.Folder @label='Products' @icon={{PackageIcon}} as |folder|>
<folder.Item @href='#all-products'>All products</folder.Item>
<folder.Item @href='#categories'>Categories</folder.Item>
</sidebar.Folder>
<sidebar.Group @label='Saved'>
<sidebar.Item @href='#starred' @icon={{StarIcon}}>
Starred
</sidebar.Item>
</sidebar.Group>
</sidebar.Body>
</Sidebar>
<p class='flex-1 p-4 text-sm text-neutral-firm'>Page content</p>
</div>
</div>
</template>
Toggle works anywhere inside the sidebar and stays visible in the rail. In
the header, put class='ml-auto' on it to push it to the end; in the footer it
lines up with the items by itself.
import { Sidebar } from 'frontile';
import { ViewIcon, SettingsIcon } from 'site/components/icons';
<template>
<div class='not-prose h-56'>
<Sidebar @label='Footer toggle' as |sidebar|>
<sidebar.Body>
<sidebar.Item @href='#overview' @icon={{ViewIcon}} @isActive={{true}}>
Overview
</sidebar.Item>
<sidebar.Item @href='#settings' @icon={{SettingsIcon}}>
Settings
</sidebar.Item>
</sidebar.Body>
<sidebar.Footer>
<sidebar.Toggle />
</sidebar.Footer>
</Sidebar>
</div>
</template>
@collapsible sets what collapsing does: icon (the default) shrinks the
sidebar to a rail, offcanvas slides it closed, and none keeps it expanded.
A closed offcanvas sidebar cannot hold the button that brings it back, so these demos use a toggle outside the sidebar.
@collapsible='icon'
@collapsible='offcanvas'
@collapsible='none'
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { Sidebar, SidebarToggle } from 'frontile';
import { ViewIcon, BookIcon } from 'site/components/icons';
class Mode {
@tracked collapsed = false;
name: string;
id: string;
constructor(name: string) {
this.name = name;
this.id = `collapse-mode-${name}`;
}
toggle = () => (this.collapsed = !this.collapsed);
}
export default class CollapseModesExample extends Component {
modes = ['icon', 'offcanvas', 'none'].map((name) => new Mode(name));
<template>
<div class='demo-stack demo-stack--wide not-prose'>
{{#each this.modes as |mode|}}
<div
class='flex h-40 overflow-hidden rounded-lg border border-neutral-soft'
>
<Sidebar
@collapsed={{mode.collapsed}}
@collapsible={{mode.name}}
@label={{mode.name}}
@class='border-e border-neutral-muted'
id={{mode.id}}
as |sidebar|
>
<sidebar.Body>
<sidebar.Item @href='#home' @icon={{ViewIcon}}>Home</sidebar.Item>
<sidebar.Item @href='#docs' @icon={{BookIcon}}>Docs</sidebar.Item>
</sidebar.Body>
</Sidebar>
<div class='flex flex-1 items-start gap-2 p-2 text-sm'>
<SidebarToggle
@collapsed={{mode.collapsed}}
@onToggle={{mode.toggle}}
@controls={{mode.id}}
/>
<code class='py-2'>@collapsible='{{mode.name}}'</code>
</div>
</div>
{{/each}}
</div>
</template>
}
On its own the sidebar keeps its collapsed state itself, starting from
@defaultCollapsed. To drive it from outside, pass @collapsed and change
it yourself: from a SidebarToggle anywhere on the page, which calls
@onToggle, or from @onCollapsedChange, which the sidebar's own Toggle
calls with the value it asks for. Give the sidebar an id and pass it to the
toggle as @controls, so its aria-controls points at the sidebar. The
Collapse modes demo above is wired this way.
<Sidebar @collapsed={{this.collapsed}} id='main-nav' as |sidebar|>
...
</Sidebar>
<SidebarToggle
@collapsed={{this.collapsed}}
@onToggle={{this.toggle}}
@controls='main-nav'
/>
In an AppLayout the layout holds this state;
put layout.SidebarToggle where you want it, such as the navbar.
The sidebar also yields its state, isCollapsed and isInDrawer, and the
actions toggle, collapse and expand, so the block can render
differently in each state. isCollapsed is true in the rail and while an
offcanvas sidebar is closed; isInDrawer is true when an AppLayout shows
the sidebar in its phone drawer. Collapse this one to swap the trial card for
a single item.
Page content
import { Button, Sidebar } from 'frontile';
import { on } from '@ember/modifier';
import { ViewIcon, RocketIcon, SparklesIcon } from 'site/components/icons';
<template>
<div class='demo-stack demo-stack--wide not-prose'>
<div
class='flex h-72 overflow-hidden rounded-lg border border-neutral-soft'
>
<Sidebar
@label='Workspace'
@class='border-e border-neutral-muted'
as |sidebar|
>
<sidebar.Header>
<SparklesIcon class='size-5 shrink-0 text-primary' />
<span class='truncate text-sm font-semibold' data-sidebar-label>
Acme
</span>
<sidebar.Toggle class='ml-auto' />
</sidebar.Header>
<sidebar.Body>
<sidebar.Item @href='#overview' @icon={{ViewIcon}} @isActive={{true}}>
Overview
</sidebar.Item>
</sidebar.Body>
<sidebar.Footer>
{{#if sidebar.isCollapsed}}
<sidebar.Item @icon={{RocketIcon}} {{on 'click' sidebar.expand}}>
Upgrade
</sidebar.Item>
{{else}}
<div class='rounded-lg border border-neutral-muted p-3 text-sm'>
<p class='font-medium'>Trial ends in 5 days</p>
<Button @size='xs' @color='primary' @class='mt-2'>
Upgrade
</Button>
</div>
{{/if}}
</sidebar.Footer>
</Sidebar>
<p class='flex-1 p-4 text-sm text-neutral-firm'>Page content</p>
</div>
</div>
</template>
@layout sets how an item arranges its icon and label:
inline (default): the label beside the icon.stacked: a small label under the icon. @shortLabel replaces the visible
text; the full label still names the link.icon: the icon alone, with the label as a tooltip.stacked and icon ignore collapsing and suit @size='rail', a narrow
column meant to stay put, so pair it with @collapsible='none'. A rail
centers its header over the items.
import { Sidebar } from 'frontile';
import {
ViewIcon,
SettingsIcon,
UserIcon,
SparklesIcon
} from 'site/components/icons';
<template>
<div class='not-prose flex h-64 flex-wrap items-start gap-8'>
<Sidebar @collapsible='none' @label='Inline' as |sidebar|>
<sidebar.Body>
<sidebar.Item @href='#overview' @icon={{ViewIcon}} @isActive={{true}}>
Overview
</sidebar.Item>
<sidebar.Item @href='#members' @icon={{UserIcon}}>
Members
</sidebar.Item>
</sidebar.Body>
</Sidebar>
<Sidebar @collapsible='none' @size='rail' @label='Stacked' as |sidebar|>
<sidebar.Header>
<SparklesIcon class='size-5 shrink-0 text-primary' />
</sidebar.Header>
<sidebar.Body>
<sidebar.Item
@href='#overview'
@layout='stacked'
@icon={{ViewIcon}}
@isActive={{true}}
>
Overview
</sidebar.Item>
<sidebar.Item
@href='#settings'
@layout='stacked'
@icon={{SettingsIcon}}
@shortLabel='Prefs'
>
Settings
</sidebar.Item>
</sidebar.Body>
</Sidebar>
<Sidebar @collapsible='none' @size='rail' @label='Icon only' as |sidebar|>
<sidebar.Body>
<sidebar.Item
@href='#overview'
@layout='icon'
@icon={{ViewIcon}}
@isActive={{true}}
>
Overview
</sidebar.Item>
<sidebar.Item @href='#members' @layout='icon' @icon={{UserIcon}}>
Members
</sidebar.Item>
</sidebar.Body>
</Sidebar>
</div>
</template>
On its own the sidebar has no background or border: it sits on its
container's surface. Draw an edge with @class, as the demos above do with
@class='border-e border-neutral-muted'. In an AppLayout the layout draws
both.
The header, body and footer share one content line, so items, group headings
and your own markup line up without padding of your own. To keep a brand in
place when the sidebar collapses, give its icon size-5, as the demos do.
@class on the sidebar or on an item is merged with the theme's classes, so a
conflicting class wins. Use it on the sidebar for another width, such as
@class='w-48'. That width holds in the rail too, so pair it with
@collapsible='none'.
import { Sidebar } from 'frontile';
import { StarIcon, ViewIcon } from 'site/components/icons';
<template>
<div class='not-prose h-32'>
<Sidebar @label='Favorites' @class='w-48' @collapsible='none' as |sidebar|>
<sidebar.Body>
<sidebar.Item @href='#all' @icon={{ViewIcon}}>All</sidebar.Item>
<sidebar.Item @href='#starred' @icon={{StarIcon}} @class='text-primary'>
Starred
</sidebar.Item>
</sidebar.Body>
</Sidebar>
</div>
</template>
Inside an AppLayout, use the yielded layout.Sidebar. It
shares the layout's state, takes the first column (or the last, with
@sidebarSide='end'), and on small screens moves into a drawer or gives way
to a BottomNav. Render one Sidebar per layout. The
AppLayout page shows each of these.
nav landmark named by @label (default Main). Give
each navigation on the page its own name.aria-current="page". A disabled item has
aria-disabled="true" and no href; a disabled button is natively disabled.@icon and @shortLabel are hidden from assistive technology, so
the full label names the link in every layout and in the rail.@badge is read after the label; give @badgeLabel when the bare value
is unclear.Group is a group named by its @label.Toggle is a button named by @label (default "Toggle sidebar"), with
aria-expanded and aria-controls pointing at the sidebar.@label. Inline it is a disclosure
(aria-expanded, aria-controls) over a group of its items. In the rail
it is a menu button, and its items are link items of a menu, so they
still open in a new tab. A closed folder keeps its items out of the tab
order.Inline:
| Key | Action |
|---|---|
| Enter or Space | On the trigger, opens or closes the folder |
| Tab | Moves through the trigger and, while open, its items |
In the icon rail:
| Key | Action |
|---|---|
| Enter, Space, ArrowDown or ArrowUp | On the trigger, opens the menu |
| Letters | Opens the menu, or moves to the next item whose label starts with them |
| ArrowDown or ArrowUp | In the menu, moves between items, skipping disabled ones |
| Enter | Follows the item's link and closes the menu |
| Escape or Tab | Closes the menu and returns focus to the trigger |
Element: HTMLElement
The sidebar navigation: a full-height nav landmark that can collapse to
an icon rail. Inside AppLayout it takes the first (or, with
@sidebarSide="end", the last) column. Below the layout's @breakpoint
the same block renders inside a Drawer instead, opened by MenuToggle,
so the sidebar is written once. It also works on its own, always inline,
with @collapsed or its own state.
| Name | Type | Default | Description |
|---|---|---|---|
class
|
string
|
- |
Classes for the sidebar, merged with the theme's so a conflicting class
wins: @class="w-72" replaces the width. A width given this way applies
whether or not the sidebar is collapsed, so pair it with
@collapsible="none". Applies to the inline sidebar, not the drawer.
|
collapsed
|
boolean
|
- |
Whether the sidebar is collapsed, for a sidebar you control. Toggle
and the yielded actions then call @onCollapsedChange and leave the
change to you. Without it the sidebar keeps its own state, starting from
@defaultCollapsed. Only used outside an AppLayout; inside one, use the
layout's @sidebarCollapsed.
|
collapsible
|
enum
|
'icon'
|
How the sidebar collapses. icon shrinks it to a rail where item labels
are visually hidden but stay available to assistive technology;
offcanvas hides it entirely while collapsed; none ignores collapse.
|
defaultCollapsed
|
boolean
|
false
|
Whether the sidebar starts collapsed when it keeps its own state (no
@collapsed). Only used outside an AppLayout.
|
label
|
string
|
'Main'
|
The accessible name of the sidebar's nav landmark. Give each navigation
on the page a distinct name.
|
layout
|
Object
|
- |
Supplied by AppLayout. Not part of the public API.
|
onCollapsedChange
|
function
|
- |
Called with the requested collapsed state when Toggle or a yielded
action changes it. Only used outside an AppLayout.
|
size
|
enum
|
'default'
|
The sidebar's width preset. default is the standard sidebar; rail is
a narrow column (80px) for a stack of icon-over-label items, usually with
@collapsible="none". It is a named preset, not a length: for any other
width, pass a width utility as @class (and set --app-sidebar-width
yourself if you read the token).
|
variant
|
enum
|
'attached'
|
The layout variant, inset or attached, which sets the sidebar's
widths and the gutter around its rows. Only used when the sidebar is
rendered outside an AppLayout; inside one it follows the layout.
|
| Name | Type | Default | Description |
|---|---|---|---|
default
*
|
Array
|
- |
Yields Header, Body and Footer sections, Item links, Folder
for a collapsible set of items, Group to label a set of items, and
Toggle, the button that collapses and expands the sidebar. It also
yields the sidebar's state, isCollapsed and isInDrawer, and the
actions toggle, collapse and expand. Place
Toggle yourself, usually in Header or Footer; there is no default
toggle. In the phone drawer Toggle renders nothing (the drawer is
always expanded and has its own close button), so the same markup works
at every width. In the icon rail, Item labels are visually
hidden but still read by screen readers; for your own markup, wrap the
text in <span data-sidebar-label> to get the same behavior.
|
Element: enum
A styled navigation link. It takes the same routing arguments as
TabNav.Item: @route renders a LinkTo and the router decides whether it
is active; @href renders a plain anchor and needs no router. The active
item carries aria-current="page". In the icon rail the label is visually
hidden but keeps naming the link, and shows as a tooltip on hover or focus.
| Name | Type | Default | Description |
|---|---|---|---|
badge
|
enum
|
- |
A count or short status shown as a pill on the icon. Nothing is shown
for undefined, null, 0 or an empty string.
|
badgeDot
|
boolean
|
- |
Supplied by BottomNav.More: shows the badge as a small dot with no
text, whatever @badge is. @badgeLabel is its screen-reader text.
Not part of the public API.
|
badgeLabel
|
string
|
- | Screen-reader text for the badge, read after the label. Defaults to the badge value. |
class
|
string
|
- | Class names added to this item's theme classes. Merged with Tailwind Merge, so a class that conflicts with a theme class wins. |
folder
|
Object
|
- |
Supplied by NavFolder: the folder this item belongs to. The item
registers itself with it so the folder can follow its active and hidden
state. Not part of the public API.
|
href
|
string
|
- |
Renders a plain anchor. Ignored when @route is given.
|
icon
|
ComponentLike
|
- | An icon component, shown before the label. In the icon rail it is the only visible part of the item. It is hidden from assistive technology. |
isActive
|
boolean
|
- |
Overrides the active state. Always wins over anything derived from the
router, and is the only source of truth when @route is not used.
|
isDisabled
|
boolean
|
false
|
Marks the link as disabled. The href is dropped as well, so the link
cannot be followed; an item with neither @href nor @route is a
button, which gets the native disabled attribute.
|
isHidden
|
boolean
|
false
|
Renders nothing at all. For items the current user may not see. |
layout
|
enum
|
'inline'
|
How the item lays out its icon and label. inline puts the label beside
the icon and follows the sidebar's icon rail; stacked puts a small label
under the icon; icon shows the icon alone, with the label as a tooltip.
stacked and icon ignore the sidebar's collapsed state.
|
menuItem
|
ListboxItem (manager, onLinkActivate bound)
|
- |
Supplied by NavFolder in the icon rail: the Dropdown menu's item
component. The item then renders as a link row of that menu (a
role="menuitem" holding the link) instead of a nav row. Not part of
the public API.
|
model
|
unknown
|
- |
A single dynamic segment for @route.
|
models
|
Array
|
- |
Dynamic segments for @route.
|
noTooltip
|
boolean
|
- |
Supplied by BottomNav.More: never shows the label as a tooltip, even
in the icon layout. Not part of the public API.
|
onActivate
|
function
|
- |
Supplied by Sidebar while it renders in the mobile drawer: called when
the item's link is clicked, so the drawer closes. Not called for a
disabled item. Not part of the public API.
|
query
|
Record<string, unknown>
|
- |
Query params for @route.
|
rail
|
boolean
|
- |
Supplied by Sidebar: whether the sidebar is drawn as the icon rail.
Not part of the public API.
|
registerOnly
|
boolean
|
- |
Supplied by NavFolder in the icon rail: the item only registers with
its folder and renders nothing, so the folder can follow its active state
while its menu is closed. Not part of the public API.
|
route
|
string
|
- |
Renders a LinkTo for this route and derives the active state from the
router. Omit it (and pass @href) to stay entirely router-free.
|
shortLabel
|
string
|
- |
Shorter text shown in place of the label in the stacked layout. The
full label stays the link's accessible name.
|
tooltipPlacement
|
enum
|
- |
Supplied by Sidebar (or BottomNav): the side of the item its
tooltip opens on.
Not part of the public API.
|
| Name | Type | Default | Description |
|---|---|---|---|
default
*
|
Array
|
- | The item's label. |
Element: HTMLDivElement
A collapsible group of navigation items, one level deep. The trigger is a
disclosure button (aria-expanded, aria-controls); the items sit in a
role="group" panel labelled by it. The folder opens when
one of its items is active, on load and whenever an item newly becomes
active, but never forces itself open otherwise. It is hidden when none of
its items is visible.
In the collapsed icon rail (not in the mobile drawer) the trigger is a
Dropdown menu button instead, and the items are the menu's link items,
beside the rail. The menu brings the keyboard model (arrows, type-ahead,
Escape returning focus to the trigger); tabbing out of it or following an
item closes it.
| Name | Type | Default | Description |
|---|---|---|---|
label
*
|
string
|
- | The folder's label, shown in its trigger. |
class
|
string
|
- | Class names added to the folder's root element. Merged with Tailwind Merge, so a class that conflicts with a theme class wins. |
defaultOpen
|
boolean
|
false
|
The initial open state when @open is not given.
|
icon
|
ComponentLike
|
- | An icon component, shown before the label. It is hidden from assistive technology. |
isHidden
|
boolean
|
false
|
Hides the folder. A folder is also hidden when none of its items is visible. |
onActivate
|
function
|
- |
Supplied by Sidebar while it renders in the mobile drawer: handed to
each item so following one closes the drawer. Not part of the public API.
|
onOpenChange
|
function
|
- | Called with the requested inline open state whenever it would change. Not called when the menu of the collapsed icon rail opens or closes. |
open
|
boolean
|
- |
Makes the open state controlled. Clicks then only call This is the inline open state. In the collapsed icon rail the folder
opens as a menu instead, whose state is its own: |
parent
|
Object
|
- |
Supplied by BottomNav.More: the container this folder belongs to. The
folder registers a handle with it that reports its children: active when
a visible child is, hidden when the folder or every child is, badged
when a visible child is. Not part of the public API.
|
rail
|
boolean
|
- |
Supplied by Sidebar: whether the sidebar is drawn as the icon rail,
where the folder opens as a menu. Not part of the public API.
|
tooltipPlacement
|
enum
|
'right'
|
Supplied by Sidebar: the side rail tooltips, and so the menu, open
on. Not part of the public API.
|
| Name | Type | Default | Description |
|---|---|---|---|
default
*
|
Array
|
- |
Yields Item, a NavItem that belongs to this folder.
|
Element: HTMLDivElement
A labelled set of sidebar items: a group named by its visible @label.
| Name | Type | Default | Description |
|---|---|---|---|
label
*
|
string
|
- | The group's heading. It is shown above the items and names the group for assistive technology. In the icon rail it is visually hidden. |
class
|
string
|
- | Class names appended to this group's theme classes. |
classes
|
Object
|
- |
Supplied by Sidebar. Not part of the public API. Without it (a group
rendered on its own) the standalone sidebar's classes are used.
|
| Name | Type | Default | Description |
|---|---|---|---|
default
*
|
Array
|
- | The group's items. |
Element: HTMLButtonElement
A button that collapses and expands the sidebar. aria-expanded is true
while the sidebar is expanded. Inside an AppLayout, below its
@breakpoint (where the sidebar is a drawer) it opens the drawer instead,
like MenuToggle, and aria-expanded follows the drawer. With
@mobileNav="bottom" there is no sidebar below the breakpoint, so there it
renders nothing.
| Name | Type | Default | Description |
|---|---|---|---|
collapsed
|
boolean
|
- |
Whether the sidebar it controls is collapsed, for aria-expanded. Only
used outside an AppLayout; inside one the button follows the layout.
|
controls
|
string
|
- |
The id of the sidebar this button controls, for aria-controls. Inside
an AppLayout it defaults to the layout's sidebar, which below the
breakpoint is the nav inside the drawer.
|
label
|
string
|
'Toggle sidebar'
|
The accessible name of the button. |
layout
|
Object
|
- |
Supplied by AppLayout. Not part of the public API.
|
onToggle
|
function
|
- |
Called when the button is pressed. Only used outside an AppLayout,
where you flip the value you pass to the Sidebar's @collapsed;
inside one the button changes the layout's state itself.
|
| Name | Type | Default | Description |
|---|---|---|---|
default
*
|
Array
|
- | Replaces the default icon with your own content. |