Mobile app shell
Top app bar and a bottom navigation bar.
Home
Annual leave left
14 days
of 25 · resets 1 January
Out today
Coming up
Thu 16 Oct · Lisbon office
mobile-app-shell.tsx
import {
LuBell,
LuCalendarDays,
LuClipboardCheck,
LuEllipsis,
LuHouse,
LuPlus,
LuSearch,
LuUsers,
} from "react-icons/lu";
import {
Avatar,
Badge,
FAB,
IconButton,
ListItem,
NavigationBar,
NavItem,
TopAppBar,
} from "@nexera-ui/react";
// Sample data
interface Person {
id: string;
name: string;
initials: string;
role: string;
team: string;
email: string;
location: string;
status: "Active" | "On leave" | "Remote" | "Invited";
}
const PEOPLE: Person[] = [
{
id: "p1",
name: "Ayesha Khan",
initials: "AK",
role: "Senior product designer",
team: "Design",
email: "ayesha.khan@northwind.io",
location: "London",
status: "Active",
},
{
id: "p2",
name: "Sara Malik",
initials: "SM",
role: "Payroll specialist",
team: "People Ops",
email: "sara.malik@northwind.io",
location: "Lisbon",
status: "On leave",
},
{
id: "p3",
name: "Ahmed Raza",
initials: "AR",
role: "Engineering manager",
team: "Engineering",
email: "ahmed.raza@northwind.io",
location: "Lahore",
status: "Remote",
},
{
id: "p4",
name: "Mia Jensen",
initials: "MJ",
role: "Product manager",
team: "Product",
email: "mia.jensen@northwind.io",
location: "Copenhagen",
status: "Active",
},
{
id: "p5",
name: "Luis Ortega",
initials: "LO",
role: "Frontend engineer",
team: "Engineering",
email: "luis.ortega@northwind.io",
location: "Madrid",
status: "Active",
},
{
id: "p6",
name: "Yuki Tanaka",
initials: "YT",
role: "Recruiter",
team: "People Ops",
email: "yuki.tanaka@northwind.io",
location: "Tokyo",
status: "Active",
},
{
id: "p7",
name: "Chloe Martin",
initials: "CM",
role: "Data analyst",
team: "Finance",
email: "chloe.martin@northwind.io",
location: "Paris",
status: "Remote",
},
{
id: "p8",
name: "Omar Haddad",
initials: "OH",
role: "Support lead",
team: "Customer",
email: "omar.haddad@northwind.io",
location: "Dubai",
status: "Invited",
},
];
const OUT_TODAY = [
{
person: PEOPLE[1],
note: "Annual leave until Fri 10 Oct",
tone: "leave" as const,
label: "Leave",
},
{ person: PEOPLE[2], note: "Working from Lahore", tone: "remote" as const, label: "Remote" },
{ person: PEOPLE[6], note: "Working from Paris", tone: "remote" as const, label: "Remote" },
].flatMap(({ person, ...rest }) => (person ? [{ person, ...rest }] : []));
/** Mobile app shell: a top app bar, a scrolling home screen, a floating action and the bottom navigation bar. */
export default function MobileAppShell() {
return (
<div className="@container bg-page px-4 py-8 @3xl:px-8">
<div className="relative mx-auto flex w-full max-w-sm flex-col overflow-hidden rounded-xl border border-default bg-page shadow-md">
<TopAppBar
title="Home"
headingLevel={2}
platform="ios"
leading="menu"
leadingLabel="Menu"
actions={
<>
<IconButton variant="ghost" platform="ios" icon={<LuSearch />} aria-label="Search" />
<IconButton
variant="ghost"
platform="ios"
icon={<LuEllipsis />}
aria-label="More actions"
/>
</>
}
/>
<div className="grid gap-5 px-4 pt-2 pb-24">
<section
aria-labelledby="mobile-shell-balance"
className="grid gap-1 rounded-lg bg-brand-primary p-4 text-brand-on-primary"
>
<h3 id="mobile-shell-balance" className="text-body-strong">
Annual leave left
</h3>
<p className="text-heading-h2">14 days</p>
<p className="text-body-small">of 25 · resets 1 January</p>
</section>
<section aria-labelledby="mobile-shell-out" className="grid gap-2">
<h3 id="mobile-shell-out" className="text-heading-h4 text-primary">
Out today
</h3>
<ul className="m-0 list-none overflow-hidden rounded-lg border border-default bg-surface p-0">
{OUT_TODAY.map(({ person, note, tone, label }) => (
<li key={person.id} className="border-b border-subtle last:border-b-0">
<ListItem
href={`#person-${person.id}`}
title={person.name}
subtitle={note}
leading={<Avatar size="lg" initials={person.initials} isDecorative />}
trailing={<Badge tone={tone} label={label} />}
/>
</li>
))}
</ul>
</section>
<section aria-labelledby="mobile-shell-next" className="grid gap-2">
<h3 id="mobile-shell-next" className="text-heading-h4 text-primary">
Coming up
</h3>
<div className="rounded-lg border border-default bg-surface">
<ListItem
href="#holiday"
icon={<LuCalendarDays />}
title="Company offsite"
subtitle="Thu 16 Oct · Lisbon office"
/>
</div>
</section>
</div>
<FAB variant="extended" icon={<LuPlus />} className="absolute end-4 bottom-24">
Request leave
</FAB>
<NavigationBar aria-label="Northwind app" platform="ios">
<NavItem href="#home" icon={<LuHouse />} label="Home" isCurrent />
<NavItem
href="#approvals"
icon={<LuClipboardCheck />}
label="Approvals"
badge="3"
badgeLabel="3 pending"
/>
<NavItem href="#team" icon={<LuUsers />} label="Team" />
<NavItem href="#inbox" icon={<LuBell />} label="Inbox" />
</NavigationBar>
</div>
</div>
);
}
More app shells and navigation blocks
- Sidebar app shellSidebar with sections, nested items, badges and a user card.
- Top bar with tabsPage title, breadcrumbs, actions and section tabs.
- Settings layoutVertical tabs on the left, a form on the right.
- Command palette⌘K search for pages, people and actions.
- Page headerTitle, description, status badge and primary actions.
- Workspace switcherSwitch organisation or create a new one.