Page Shell - National Design System

The body structure every NDS page is built on, covering the chrome regions, the content layout grid, and the classes that switch between page shapes.

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.

body (console pages add .nds-full-width) ├── header (top bar + main navigation, see Header) ├── main │ ├── section.nds-hero-section.nds-sub (page hero; the home shape uses the hero slider) │ └── div.nds-content-layout (shape and modifier classes go here) │ ├── aside.nds-sidemenu (side menu; requires .nds-wSideMenu, first child) │ └── div.nds-main-content.nds-stripe (.nds-stripe turns on section striping) │ ├── section.nds-content-section (page sections, repeated) │ └── ... └── footer.nds-footer (see Footer)

Each chrome region has its own reference: Head, Header, Hero, and Footer. This page covers what sits between them: nds-content-layout and the classes that shape it.

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.

div.nds-content-layout.nds-wSideMenu ├── aside.nds-sidemenu (first child; markup on the Side Menu page) └── div.nds-main-content

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.

div.nds-content-layout.nds-wSideInfo └── div.nds-main-content └── section.nds-content-section.nds-sideinfo-section └── div.nds-section-body ├── aside.nds-sideinfo.nds-md.nds-sticky.nds-top │ └── nav.nds-toc (table of contents) └── div.nds-info-content (the page content)

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-greenSolid brand surface
nds-gradient-primary, nds-gradient-greenBrand gradient
nds-neutralSolid dark surface
nds-brandTinted brand surface with an inset shadow
nds-user-feedback-sectionFeedback 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

Responsive Side Column

The side menu holds a fixed-width column on desktop and collapses into a compact menu control on mobile, with no extra classes.

Centered Content Width

Content is capped at the system max width and centered, with the same responsive gutter the chrome uses.

Edge-to-Edge Switch

One class on body widens the top bar, navigation, content, and footer together for console pages.

Section Striping

Add nds-stripe to nds-main-content and sections alternate background color in plain layouts, skipping colored and status sections.

Card View

One layout class renders each section as a raised card, sized and spaced for record and profile pages.

Direction Aware

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-layout per page and put all page content inside nds-main-content, structured as sections. Never nest one content layout inside another
  • An aside.nds-sidemenu shows only when the layout carries nds-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-width on body is the single switch, and the hero moves inside nds-main-content so it sits beside the side menu
  • nds-full-width sets one variable, --nds-content-MaxWidth, and only nds-* 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-width by design: the page widens around the cards without flattening them
  • Use the minimal shape for sign in, OTP, and other focused flows. nds-middle centers 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-section next to the text it tracks
  • Text-heavy pages can flatten the page hero with nds-flat on 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.

ClassApplies toDescription
nds-wSideMenulayoutTwo-column grid on desktop; required for the side menu aside to show
nds-wSideInfolayoutMarks the side info arrangement; the aside itself sits inside the content section
nds-cardViewlayoutRenders each section as a raised card with tighter titles and spacing
nds-content-wrapperlayoutApplies the standard page gutter directly to the layout (minimal shape)
nds-middlelayoutFull viewport height with content centered vertically and horizontally
nds-postlayoutRemoves the first section's top padding, for article-style pages
nds-stripends-main-contentSections alternate background color; off without it, and card view never stripes
nds-oddnds-main-contentFlips the stripe parity, so the first section is tinted; needs nds-stripe
nds-full-widthbodyEdge-to-edge chrome and content for console pages; card view keeps its gutters
nds-page-bgbodyBackground 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-topaside.nds-sidemenuRenders the side menu as a bar above the content instead of a column
nds-flathero sectionRemoves the hero background and shadow for text-heavy pages

CSS Custom Properties

Property Default Description
--layout-min-height400pxMinimum height of the content area
--layout-gap0Gap between the side column and the content
--main-padding-block0Vertical padding on nds-main-content
--main-padding-inline0Horizontal padding on nds-main-content
--main-gap0Gap between sections inside nds-main-content
--nds-sidemenu-width260pxSide column width (global token)
--nds-content-MaxWidth1280pxContent max width (global token; nds-full-width sets it to 100%)
--bg-imgnot setBackground image behind the page on body.nds-page-bg. Set it as a url() value
--bg-opacity-top80%Strength of the color veil over the image at the top of the page. Higher values hide more of the image
--bg-opacity-bottom80%Strength of the same veil at the bottom of the page
Last Modified Date: 22/08/2026 - 04:08 AM
Was this page useful?
60% of users said Yes from 2843 Feedbacks