Dashboard layout
A dashboard shell with a side navigation, a page header, three stat tiles and a recent orders list. The navigation sits above the content below 768px.
Preview
Overview
-
Revenue
$48,210
-
Orders
1,284
-
Refund rate
1.8%
Recent orders
- Lina Haddad$320.00
- Omar Siddiqui$86.50
- Grace Okafor$1,140.00
With utility classes
The markup of the preview. Classes come from the prebuilt dist/nuvoui.min.css, or from your own build with $generate-utility-classes: true.
HTML
<div class="grid cols-12@md bg-base text-regular border rounded-lg overflow-hidden">
<nav class="col-span-3@md col-span-2@lg bg-alternate p-4" aria-label="Dashboard">
<p class="font-semibold m-0 mb-3">Northwind</p>
<ul class="flex col@md gap-1 m-0 p-0 overflow-x-auto text-sm" role="list">
<li><a class="block whitespace-nowrap bg-selected text-brand font-medium rounded-md px-3 py-2" href="/dashboard/" aria-current="page">Overview</a></li>
<li><a class="block whitespace-nowrap text-muted hover:bg-hover hover:text-regular rounded-md px-3 py-2" href="/dashboard/orders/">Orders</a></li>
<li><a class="block whitespace-nowrap text-muted hover:bg-hover hover:text-regular rounded-md px-3 py-2" href="/dashboard/customers/">Customers</a></li>
<li><a class="block whitespace-nowrap text-muted hover:bg-hover hover:text-regular rounded-md px-3 py-2" href="/dashboard/settings/">Settings</a></li>
</ul>
</nav>
<section class="col-span-9@md col-span-10@lg p-4 p-6@md" aria-labelledby="dashboard-title">
<div class="flex wrap between x-center gap-3 mb-6">
<h3 class="text-xl font-semibold m-0" id="dashboard-title">Overview</h3>
<button class="rounded-md text-sm" type="button">Export report</button>
</div>
<ul class="grid cols-1 cols-3@sm gap-4 m-0 p-0" role="list">
<li class="bg-surface border rounded-lg p-4">
<p class="text-sm text-muted m-0">Revenue</p>
<p class="text-2xl font-semibold m-0 mt-1">$48,210</p>
</li>
<li class="bg-surface border rounded-lg p-4">
<p class="text-sm text-muted m-0">Orders</p>
<p class="text-2xl font-semibold m-0 mt-1">1,284</p>
</li>
<li class="bg-surface border rounded-lg p-4">
<p class="text-sm text-muted m-0">Refund rate</p>
<p class="text-2xl font-semibold m-0 mt-1">1.8%</p>
</li>
</ul>
<section class="bg-surface border rounded-lg mt-6" aria-labelledby="orders-title">
<h4 class="text-base font-semibold m-0 px-4 py-3 border-b" id="orders-title">Recent orders</h4>
<ul class="m-0 p-0 text-sm" role="list">
<li class="flex between gap-4 px-4 py-3 border-b"><span>Lina Haddad</span><span class="text-muted">$320.00</span></li>
<li class="flex between gap-4 px-4 py-3 border-b"><span>Omar Siddiqui</span><span class="text-muted">$86.50</span></li>
<li class="flex between gap-4 px-4 py-3"><span>Grace Okafor</span><span class="text-muted">$1,140.00</span></li>
</ul>
</section>
</section>
</div>With apply()
The same result with BEM class names and no utility classes. @use "@nuvoui/core" as *; emits the tokens and base styles, and each apply() writes one rule.
SCSS
@use "@nuvoui/core" as *;
.dashboard {
@include apply(
grid, // display: grid
cols(12) md, // 12 grid columns from md (768px) up
bg(base), // page background, follows the theme
text-color(regular), // regular text color, follows the theme
border(1), // 1px border (width key 1), regular color
rounded(lg), // corner radius: size key lg (0.75rem)
overflow-hidden // clip content that overflows the box
);
}
.dashboard__nav {
@include apply(
col-span(3) md, // span 3 of 12 columns from md (768px) up
col-span(2) lg, // span 2 of 12 columns from lg (1024px) up
p(4), // padding: spacing key 4 (1rem)
bg(alternate) // alternate background, follows the theme
);
}
.dashboard__brand {
@include apply(
m(0), // margin: 0
mb(3), // bottom margin: spacing key 3 (0.75rem)
font(semibold) // font weight: semibold (600)
);
}
// A scrolling row below md, a column from md
.dashboard__menu {
@include apply(
flex, // display: flex
col md, // flex direction: column from md (768px) up
gap(1), // gap: spacing key 1 (0.25rem)
m(0), // margin: 0
p(0), // padding: 0
overflow-x-auto, // scroll sideways when the row is too wide
font-size(sm) // font size key sm (0.875rem)
);
}
.dashboard__link {
@include apply(
block, // display: block
px(3), // horizontal padding: spacing key 3 (0.75rem)
py(2), // vertical padding: spacing key 2 (0.5rem)
rounded(md), // corner radius: size key md (0.5rem)
whitespace-nowrap, // keep the text on one line
text-color(muted), // muted text color, follows the theme
bg(hover) hover, // hover background on hover
text-color(regular) hover // regular text color on hover
);
&[aria-current="page"] {
@include apply(
bg(selected), // selected item background
text-color(brand), // brand text color
font(medium) // font weight: medium (500)
);
}
&:focus-visible {
outline: token(border-focus-width) solid token(border-focus);
outline-offset: token(border-focus-offset);
}
}
.dashboard__main {
@include apply(
col-span(9) md, // span 9 of 12 columns from md (768px) up
col-span(10) lg, // span 10 of 12 columns from lg (1024px) up
p(4), // padding: spacing key 4 (1rem)
p(6) md // padding key 6 (1.5rem) from md (768px) up
);
}
.dashboard__header {
@include apply(
flex, // display: flex
wrap, // let items wrap onto new lines
between, // main axis: space between (justify-content)
x-center, // cross axis: center (align-items)
gap(3), // gap: spacing key 3 (0.75rem)
mb(6) // bottom margin: spacing key 6 (1.5rem)
);
}
.dashboard__title {
@include apply(
m(0), // margin: 0
font-size(xl), // font size key xl (1.5rem)
font(semibold) // font weight: semibold (600)
);
}
.dashboard__button {
@include apply(
rounded(md), // corner radius: size key md (0.5rem)
font-size(sm) // font size key sm (0.875rem)
);
}
.dashboard__stats {
@include apply(
grid, // display: grid
cols(1), // one grid column
cols(3) sm, // three columns from sm (640px) up
gap(4), // gap: spacing key 4 (1rem)
m(0), // margin: 0
p(0) // padding: 0
);
}
.dashboard__stat {
@include apply(
p(4), // padding: spacing key 4 (1rem)
bg(surface), // surface background, follows the theme
border(1), // 1px border (width key 1), regular color
rounded(lg) // corner radius: size key lg (0.75rem)
);
}
.dashboard__label {
@include apply(
m(0), // margin: 0
font-size(sm), // font size key sm (0.875rem)
text-color(muted) // muted text color, follows the theme
);
}
.dashboard__value {
@include apply(
m(0), // margin: 0
mt(1), // top margin: spacing key 1 (0.25rem)
font-size(2xl), // font size key 2xl (1.75rem)
font(semibold) // font weight: semibold (600)
);
}
.dashboard__panel {
@include apply(
mt(6), // top margin: spacing key 6 (1.5rem)
bg(surface), // surface background, follows the theme
border(1), // 1px border (width key 1), regular color
rounded(lg) // corner radius: size key lg (0.75rem)
);
}
.dashboard__panel-title {
@include apply(
m(0), // margin: 0
px(4), // horizontal padding: spacing key 4 (1rem)
py(3), // vertical padding: spacing key 3 (0.75rem)
font-size(base), // font size key base (1rem)
font(semibold), // font weight: semibold (600)
border-bottom(1) // 1px bottom border (width key 1), regular color
);
}
.dashboard__orders {
@include apply(
m(0), // margin: 0
p(0), // padding: 0
font-size(sm) // font size key sm (0.875rem)
);
}
.dashboard__order {
@include apply(
flex, // display: flex
between, // main axis: space between (justify-content)
gap(4), // gap: spacing key 4 (1rem)
px(4), // horizontal padding: spacing key 4 (1rem)
py(3), // vertical padding: spacing key 3 (0.75rem)
border-bottom(1), // 1px bottom border (width key 1), regular color
border-bottom(0) last-child // no bottom border when it is the last child
);
}
.dashboard__amount {
@include apply(text-color(muted)); // muted text color, follows the theme
}HTML
<div class="dashboard">
<nav class="dashboard__nav" aria-label="Dashboard">
<p class="dashboard__brand">Northwind</p>
<ul class="dashboard__menu" role="list">
<li><a class="dashboard__link" href="/dashboard/" aria-current="page">Overview</a></li>
<li><a class="dashboard__link" href="/dashboard/orders/">Orders</a></li>
<li><a class="dashboard__link" href="/dashboard/customers/">Customers</a></li>
<li><a class="dashboard__link" href="/dashboard/settings/">Settings</a></li>
</ul>
</nav>
<section class="dashboard__main" aria-labelledby="dashboard-title">
<div class="dashboard__header">
<h3 class="dashboard__title" id="dashboard-title">Overview</h3>
<button class="dashboard__button" type="button">Export report</button>
</div>
<ul class="dashboard__stats" role="list">
<li class="dashboard__stat">
<p class="dashboard__label">Revenue</p>
<p class="dashboard__value">$48,210</p>
</li>
<li class="dashboard__stat">
<p class="dashboard__label">Orders</p>
<p class="dashboard__value">1,284</p>
</li>
<li class="dashboard__stat">
<p class="dashboard__label">Refund rate</p>
<p class="dashboard__value">1.8%</p>
</li>
</ul>
<section class="dashboard__panel" aria-labelledby="orders-title">
<h4 class="dashboard__panel-title" id="orders-title">Recent orders</h4>
<ul class="dashboard__orders" role="list">
<li class="dashboard__order"><span>Lina Haddad</span><span class="dashboard__amount">$320.00</span></li>
<li class="dashboard__order"><span>Omar Siddiqui</span><span class="dashboard__amount">$86.50</span></li>
<li class="dashboard__order"><span>Grace Okafor</span><span class="dashboard__amount">$1,140.00</span></li>
</ul>
</section>
</section>
</div>Tokens used
Every color comes from a theme token, so the recipe follows the light, dark and inverse themes with no extra CSS.
bg-base,bg-surface,bg-alternate- Three surface levels: the page, the tiles and panel, and the side navigation.
text-regular,text-muted- Values and labels.
border-regular- Tile, panel and row rules.
bg-selected,text-brand- The current page in the navigation, matched on aria-current="page" in the SCSS version.
bg-hover- Navigation link hover.
brand,text-on-brand,border-focus- The export button and the focus ring, from the base layer.