Layout
<ahi-layout> | AhiLayout
Layout is used to create the main layout of an app.
<!-- Inspect the templates/layout/index.html file to see the actual source code for this example -->
<iframe
loading="lazy"
style="visibility:hidden;min-height:550px;" onload="this.style.visibility='visible';"
sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"
title="Layout template demo"
src="../../templates/layout/">
</iframe>
Navigation rail
On a wide screen the navigation is either opened at its full width or hidden off-screen, and the hidden state returns on hover through a brief “peek”. A touch tablet has no hover, so peek is unreachable there: the navigation is either 250px of a 834px screen or two taps away behind the toggle.
Add nav-rail and the collapsed state becomes a narrow icon-only rail instead of nothing. Every
top-level item stays visible and one tap away, and the content column keeps most of the width it would have
gained by hiding the navigation altogether.
<ahi-layout nav-rail persist-nav-state>
<ahi-navigation slot="nav">
<ahi-nav-item icon="home" href="/">Home</ahi-nav-item>
<ahi-nav-item icon="calendar" href="/schedule">Schedule</ahi-nav-item>
</ahi-navigation>
<div>Main content</div>
</ahi-layout>
nav-rail is a preference, not a state. nav-open still says whether the navigation
is expanded; nav-rail says what the collapsed form looks like. That is why toggling out of the
expanded state returns to the rail rather than to nothing, and why persist-nav-state needs no
extra key — the nav-open value it already stores restores the right one of the two.
Some consequences worth knowing:
-
It applies to wide screens only. Below 768px the navigation is a drawer, and there is no
room for a rail beside it.
nav-railis ignored there. - A railed layout starts collapsed. The rail is already on screen, so starting collapsed costs the reader nothing and keeps the content column at full width, which is the point of asking for one.
- Peek does not apply. There is nothing hidden to reveal, so hover and focus leave the rail alone.
- The navigation is not resizable while railed. The rail is a fixed width, so the resize handle is hidden the same way it is on a narrow screen.
-
The toggle moves into the top of the rail. It is what expands the rail back to its
labels, so it is placed as the rail’s first item rather than left floating over the content. That is the
same position
ahi-navigationrenders itsheaderslot in — a logo there and the toggle will sit on top of each other, so hide the header while railed if you use one.
Choosing when to use it
nav-rail is deliberately consumer-selected rather than a width AKU picks for you. Whether a
rail beats a hidden navigation depends on how many top-level destinations an app has and how wide its
content needs to be — questions the component cannot answer. Set the attribute from whatever breakpoint
policy your app already has.
Sizing
The rail is one interactive target plus the padding around it:
--layout-nav-rail-width: calc(var(--ahi-target-min-size) + var(--ahi-space-4) * 2 + var(--ahi-space-2) * 2);
Because --ahi-target-min-size follows the pointer rather than the viewport, a touch device gets
a rail sized for a thumb and a mouse-driven desktop gets a more compact one, without either being inferred
from screen width. Override --layout-nav-rail-width if you need a different figure.
Telling slotted navigation to render icon-only
While railed, the layout sets --ahi-nav-rail: 1 on its navigation region.
Nav Item reads it and drops its label, keeping the icon. The
signal is a custom property rather than an attribute because it inherits through the flat tree — down into
the slotted <ahi-navigation> and on into each <ahi-nav-item>’s own
shadow root — which no attribute selector can do across two shadow boundaries.
Custom navigation content can read the same property:
.my-nav-label {
display: block;
}
/* 1 while the layout is railed, otherwise unset. */
@container style(--ahi-nav-rail: 1) {
.my-nav-label {
display: none;
}
}
Give any item you want to survive the rail an icon; an item with no icon has nothing left to
show once its label is dropped.
Theming
Accent color
AKU provides a concept called accent color that supports both light and dark themes. To get
started with using accent color, first remove all themes from the <head> section of the
application and only leave the default light theme that we’ll use as a basis:
<link rel="stylesheet" href="/node_modules/@azaleahealth/azalea-kit-ui/dist/themes/light.css" />
The theme ships defaults for these — --ahi-color-blue-600 for the accent and white on top of it
— so a plain install already paints correctly and you can skip this section entirely.
To use your own brand color instead, add the following after the light theme, replacing
accent-color with a hex value and text-on-accent-color with one that offers the
necessary 4.5:1 contrast ratio against it:
<style>
:root {
--ahi-color-accent: accent-color;
--ahi-color-text-on-accent: text-on-accent-color;
}
</style>
Top bar color
For applications that utilize the Top Bar component, AKU provides
slightly more control over the visual appearance. For this purpose, we have a CSS Custom Property named
var(--ahi-color-accent-secondary), which defaults to --ahi-color-blue-700 — the
darker step, because this is the surface that carries body-sized white text, where it measures 7.58:1. It
can be overridden to customize the background color of the top bar and navigation header:
To get started using this feature, add the following styles and replace color with a custom hex
value that offers at least 4.5:1 contrast ratio against white text:
<style>
:root {
--ahi-color-accent-secondary: color;
}
</style>
Note that the text and interface elements inside the top bar and navigation header use white text by
default. Although we do not recommend changing this, you can customize this color by using the
--ahi-color-text-on-accent-secondary token.
Best practices
-
Layout uses the
<main>element internally which is an HTML sectioning element and defines an ARIA landmark role. For that reason, you should never put the layout component inside another HTML landmark.
Related components
- To visually group content in a layout section, use the Card component.
- To layout a set of smaller components, use the Stack component.
Importing
To import this component using a script tag:
<script type="module" src="/path/to/azalea-kit-ui/dist/components/layout/layout.js"></script>
To import this component using a bundler:
import '@azaleahealth/azalea-kit-ui/dist/components/layout/layout.js';
Slots
| Name | Description |
|---|---|
| (default) | The default main section content. |
nav
|
Used to place content inside the navigation sidebar. |
top-bar
|
Used to place the Top Bar component. |
header
|
Used to place content inside the header section. This slot can be made sticky by utilizing the
sticky property.
|
footer
|
Used to place content inside the footer section. This slot can be made sticky by utilizing the
stickyFooter property.
|
nav-toggle
|
Used to place a custom nav-toggle component, for cases where you might need to add a tooltip. |
Learn more about using slots.
Properties
| Name | Description | Type | Default | |
|---|---|---|---|---|
navOpen
nav-open
|
Controls whether the navigation is hidden off-screen or not. Defaults to true for wide
viewports, and false otherwise.
|
boolean
|
- | |
persistNavState
persist-nav-state
|
Controls whether the navigation’s open/closed state is persisted across page loads. This is useful for multi-page apps, where clicks on links trigger a full page load. |
boolean
|
false
|
|
syncNavState
sync-nav-state
|
Controls whether the navigation’s open/closed state and width is synced across tabs/windows on the same origin. This is useful for long-lived app sessions where you may have multiple tabs/windows open at once. |
boolean
|
false
|
|
navRail
nav-rail
|
Controls whether a wide-screen navigation that is not opened stays on screen as a narrow icon-only
rail, rather than hiding off-screen behind the toggle. This is a preference, not a state:
nav-open still says whether the nav is expanded, and this says what the collapsed form
looks like. That is what makes toggling out of opened return to the rail rather than to
nothing, and it is why persist-nav-state needs no new key — the persisted
nav-open already restores the right one of the two. Off by default, so a consumer that
does not opt in renders exactly as before. Only wide screens are affected; below 768px the nav is a
drawer and there is no room for a rail.
|
boolean
|
false
|
|
padding
|
Controls the padding of the default main section slot. When set to “none”, the nav and header slots will still have padding. |
'm' | 'none'
|
'm'
|
|
sticky
|
Controls whether the layout’s header has sticky positioning. |
boolean
|
false
|
|
stickyFooter
sticky-footer
|
Controls whether the layout’s footer has sticky positioning. |
boolean
|
false
|
|
isNarrow
|
A getter whose values reflects whether the layout component considers the viewport to be narrow or not. A narrow viewport is considered to be less than 768px wide. |
boolean
|
- | |
updateComplete |
A read-only promise that resolves when the component has finished updating. |
Learn more about properties and attributes.
Dependencies
This component automatically imports the following dependencies.
<ahi-button><ahi-icon><ahi-nav-toggle><ahi-spinner>