Page Shell Anatomy
Every NDS page shares one body structure: the chrome regions around a single content layout grid that holds the page sections. Do not write this structure by hand. Copy the full body of a built page whose shape matches yours, then swap the content. The shapes table names the source page for each shape.
Page Shapes
Four shapes cover the system. Pick the row that matches your page and copy its source page as the starting point.
| Shape | Structure | Copy from |
|---|---|---|
| Home | Bare nds-content-layout, no side column. The hero slider is the first child of main. |
Home Page Template, whose source carries the whole shell in one file; or this site's own Home page |
| Content page | nds-content-layout with the sub hero first in main. Add nds-wSideMenu and the aside for a side menu, or nds-cardView for card-style sections. |
Services List; Program for card view with a side menu; any documentation page on this site, this one included, for a plain side menu |
| Minimal | nds-content-layout nds-content-wrapper nds-middle, no chrome at all: no header, footer, or hero. body carries nds-page-bg and its background knobs. Content centers in the viewport. |
Sign in |
| Console | nds-content-layout nds-wSideMenu plus nds-full-width on body. The hero moves inside nds-main-content so it sits beside the side menu. |
Admin Console |
Two of these pages carry the same Home shape but are authored differently, and the difference matters when you read the source. This site's own home page leaves the header, hero and footer to its Jekyll layout, so its source file holds only the sections. The Home Page Template uses the shell layout instead, which renders the document and the scripts and nothing else, so the page composes its own header, hero, content layout and footer and the source reads as a complete page. Read the template when you want the whole shape in one file. Either way the built HTML under _site/ is what a project copies.
Every DGA template uses the content page shape with the side menu off. Contact Us, Content, Form, and Service add side info. The 404 template is the one exception: it ships its own centered wrapper with no content layout.
Side Menu and Side Info
Both are toggles on top of a shape, not shapes of their own. They attach at different levels: the side menu is a layout column, side info lives inside the content.
Side Menu
nds-wSideMenu on the layout creates a two-column grid on desktop and shows the aside.nds-sidemenu placed as its first child. Without the class, the layout hides any direct aside child, so the two always ship together. On mobile the grid collapses to one column and the menu becomes a compact control. Add nds-top to the aside to render it as a bar above the content instead of a column. The aside's own markup is on the Side Menu page.
Side Info
nds-wSideInfo goes on the layout, but the aside is not a layout child. It sits inside the content, in a section marked nds-sideinfo-section, beside the text it tracks. The aside's own markup is on the Side Info page, and the Content template ships the full arrangement.
Section Striping
A striped page alternates the background color of its sections down the page. Striping is off until you ask for it. One class turns it on, and a second flips which sections carry the tint.
Stripe Classes
Add nds-stripe to nds-main-content. Every second section then takes the --background-stripe color, and the first section keeps the page background.
Add nds-odd beside it to flip the parity. The first section takes the tint instead, then every second one after it. Use it when the page opens on a section that must stand apart from the hero above it. nds-odd does nothing on its own.
<!-- Tints the 2nd, 4th, and 6th section -->
<div class="nds-main-content nds-stripe">
<!-- Tints the 1st, 3rd, and 5th section -->
<div class="nds-main-content nds-stripe nds-odd">
Both classes work with a side menu and at every screen width. Striping counts sections, not wrappers, so a merged or added section flips the parity of every section below it. The Section page covers what that means for stacked wrappers.
Skipped Sections
A section that paints its own background is skipped in both parities, so a stripe never fights a colored surface. The section still holds its place in the count, so the sections around it stay on the pattern.
| Section class | Reason |
|---|---|
nds-primary, nds-green | Solid brand surface |
nds-gradient-primary, nds-gradient-green | Brand gradient |
nds-neutral | Solid dark surface |
nds-brand | Tinted brand surface with an inset shadow |
nds-user-feedback-section | Feedback block with a surface of its own |
The last-modified strip is the one section handled apart. It reads as part of the section above it, so it takes the opposite parity and always matches that section.
Card view never stripes, whichever classes you set. Each section paints as a raised card there, and a tint behind the card reads as a mistake.
Built-in Features
The side menu holds a fixed-width column on desktop and collapses into a compact menu control on mobile, with no extra classes.
Content is capped at the system max width and centered, with the same responsive gutter the chrome uses.
One class on body widens the top bar, navigation, content, and footer together for console pages.
Add nds-stripe to nds-main-content and sections alternate background color in plain layouts, skipping colored and status sections.
One layout class renders each section as a raised card, sized and spaced for record and profile pages.
The shell is built on logical properties, so the same markup lays out correctly in RTL and LTR.
Usage Guidelines
Best Practices
- Start every page by copying the shell of a built page whose shape matches, then swap the content. A hand-assembled shell tends to lose the wrapper classes that carry width, centering, and background behavior
- Keep one
nds-content-layoutper page and put all page content insidends-main-content, structured as sections. Never nest one content layout inside another - An
aside.nds-sidemenushows only when the layout carriesnds-wSideMenu. Without the class the layout hides any direct aside child, so a menu that does not appear usually means the class is missing - Use the console shape for admin and back-office pages.
nds-full-widthonbodyis the single switch, and the hero moves insidends-main-contentso it sits beside the side menu nds-full-widthsets one variable,--nds-content-MaxWidth, and onlynds-*regions read it. Non-NDS pages in the same document are unaffected, so the class stays in the markup and needs no per-route toggle- Card view keeps its gutters and card gaps under
nds-full-widthby design: the page widens around the cards without flattening them - Use the minimal shape for sign in, OTP, and other focused flows.
nds-middlecenters the content in the viewport, and the footer is omitted - Side info is content-level, not a layout column. Keep the aside inside its
nds-sideinfo-sectionnext to the text it tracks - Text-heavy pages can flatten the page hero with
nds-flaton the hero section. See Hero for the hero's own variants
Framework Wrappers
React, Vue, and Angular add elements the shell does not expect. The shell styles direct children, so one extra element in the wrong place breaks the layout. Two places matter.
The mount root. A framework mounts into an element inside body, such as <div id="root">. That element sits between body and the chrome. body is a vertical flex column, and main grows to fill the space left over. A mount root breaks that chain, so the footer sits in the middle of the page when the content is short. Give the mount root display: contents, or pass the same flex rules through it. Nothing else in the shell depends on that position: chrome width, content width, section width, striping, and the side menu are all unaffected.
/* The mount root disappears from the layout.
The id depends on the stack: #root, #app, app-root. */
#root { display: contents; }
/* Or, when the app styles, measures, or positions the mount root itself. */
#root { flex: 1; display: flex; flex-direction: column; }
Wrappers inside the layout. Return a fragment from a component, so the sections land where the shell expects them. A plain div inside nds-content-layout takes the side menu's grid column, and the page then collapses to the width of that column. A plain div inside nds-main-content sets no width of its own, so narrow content such as a sign-in form pulls away from the page edges. Sections set their own full width, which is why the wrapper is the part that breaks.
Modifier Classes
These classes change page layout, so they must be in the markup the browser paints first. A class added from JavaScript after the app mounts costs one frame at the wrong shape. On a server-rendered page, write the class in the template. In a client-routed app where the class depends on the route, set it with a synchronous inline script that is the first child of body, before the framework mounts. A mount effect runs too late.
| Class | Applies to | Description |
|---|---|---|
nds-wSideMenu | layout | Two-column grid on desktop; required for the side menu aside to show |
nds-wSideInfo | layout | Marks the side info arrangement; the aside itself sits inside the content section |
nds-cardView | layout | Renders each section as a raised card with tighter titles and spacing |
nds-content-wrapper | layout | Applies the standard page gutter directly to the layout (minimal shape) |
nds-middle | layout | Full viewport height with content centered vertically and horizontally |
nds-post | layout | Removes the first section's top padding, for article-style pages |
nds-stripe | nds-main-content | Sections alternate background color; off without it, and card view never stripes |
nds-odd | nds-main-content | Flips the stripe parity, so the first section is tinted; needs nds-stripe |
nds-full-width | body | Edge-to-edge chrome and content for console pages; card view keeps its gutters |
nds-page-bg | body | Background image on the whole page, with a layer of the page background color over it. The minimal shape uses it. Set --bg-img and the opacity knobs below |
nds-top | aside.nds-sidemenu | Renders the side menu as a bar above the content instead of a column |
nds-flat | hero section | Removes the hero background and shadow for text-heavy pages |
CSS Custom Properties
| Property | Default | Description |
|---|---|---|
--layout-min-height | 400px | Minimum height of the content area |
--layout-gap | 0 | Gap between the side column and the content |
--main-padding-block | 0 | Vertical padding on nds-main-content |
--main-padding-inline | 0 | Horizontal padding on nds-main-content |
--main-gap | 0 | Gap between sections inside nds-main-content |
--nds-sidemenu-width | 260px | Side column width (global token) |
--nds-content-MaxWidth | 1280px | Content max width (global token; nds-full-width sets it to 100%) |
--bg-img | not set | Background image behind the page on body.nds-page-bg. Set it as a url() value |
--bg-opacity-top | 80% | Strength of the color veil over the image at the top of the page. Higher values hide more of the image |
--bg-opacity-bottom | 80% | Strength of the same veil at the bottom of the page |