v1.6.x-dev NDS IQ v6

Swiper - National Design System

A horizontal slider for hero banners, image galleries, and multi-card decks, with responsive slides-per-view, optional peek previews, and lazy-loaded images.

Hero Slider

Full-bleed hero carousel showing one slide at a time. Use this when each slide is a marketing message, banner, or call to action that should fill the hero area.

Welcome to Our Platform

Discover innovative solutions for your digital needs

<div class="nds-swiper nds-hero nds-oncolor"> <div class="nds-swiper-wrapper"> <div class="nds-swiper-slide"> <div class="slide-content" style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); min-height: 400px; display: flex; align-items: center; justify-content: center; padding: 2rem; border-radius: 8px;"> <div style="max-width: 800px; text-align: center;"> <h2 style="color: white; font-size: 2.5rem; font-weight: var(--font-weight-bold); margin-bottom: 1rem;">Welcome to Our Platform</h2> <p style="color: white; font-size: 1.25rem; margin-bottom: 2rem; opacity: 0.95;">Discover innovative solutions for your digital needs</p> <button class="nds-btn nds-primary nds-lg nds-oncolor"> <span class="nds-label">Get Started</span> </button> </div> </div> </div> <div class="nds-swiper-slide" hidden> <div class="slide-content" style="background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); min-height: 400px; display: flex; align-items: center; justify-content: center; padding: 2rem; border-radius: 8px;"> <div style="max-width: 800px; text-align: center;"> <h2 style="color: white; font-size: 2.5rem; font-weight: var(--font-weight-bold); margin-bottom: 1rem;">Powerful Features</h2> <p style="color: white; font-size: 1.25rem; margin-bottom: 2rem; opacity: 0.95;">Built with the latest technology and best practices</p> <button class="nds-btn nds-primary nds-lg nds-oncolor"> <span class="nds-label">Learn More</span> </button> </div> </div> </div> <div class="nds-swiper-slide" hidden> <div class="slide-content" style="background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); min-height: 400px; display: flex; align-items: center; justify-content: center; padding: 2rem; border-radius: 8px;"> <div style="max-width: 800px; text-align: center;"> <h2 style="color: white; font-size: 2.5rem; font-weight: var(--font-weight-bold); margin-bottom: 1rem;">Start Your Journey</h2> <p style="color: white; font-size: 1.25rem; margin-bottom: 2rem; opacity: 0.95;">Join thousands of satisfied users today</p> <button class="nds-btn nds-primary nds-lg nds-oncolor"> <span class="nds-label">Join Now</span> </button> </div> </div> </div> </div> <div class="nds-swiper-navigation" hidden> <div class="nds-swiper-buttons"> <button class="nds-btn nds-subtle nds-icon-only nds-oncolor nds-prev" aria-label="Previous slide"></button> <button class="nds-btn nds-subtle nds-icon-only nds-oncolor nds-next" aria-label="Next slide"></button> </div> <div class="nds-swiper-pagination"></div> </div> </div>

Hero with Images

Hero slider where each slide is a full-bleed image. Pick this when the imagery itself carries the message: photo galleries, campaign banners, or visual storytelling at the top of a page.

Landscape 1
<div class="nds-swiper nds-hero nds-oncolor"> <div class="nds-swiper-wrapper"> <div class="nds-swiper-slide"> <img data-src="https://picsum.photos/id/1015/800/450" alt="Landscape 1" style="width: 100%; height: 450px; object-fit: cover; border-radius: 8px;"> </div> <div class="nds-swiper-slide" hidden> <img data-src="https://picsum.photos/id/1018/800/450" alt="Landscape 2" style="width: 100%; height: 450px; object-fit: cover; border-radius: 8px;"> </div> <div class="nds-swiper-slide" hidden> <img data-src="https://picsum.photos/id/1039/800/450" alt="Landscape 3" style="width: 100%; height: 450px; object-fit: cover; border-radius: 8px;"> </div> <div class="nds-swiper-slide" hidden> <img data-src="https://picsum.photos/id/1043/800/450" alt="Landscape 4" style="width: 100%; height: 450px; object-fit: cover; border-radius: 8px;"> </div> <div class="nds-swiper-slide" hidden> <img data-src="https://picsum.photos/id/870/800/450" alt="Landscape 5" style="width: 100%; height: 450px; object-fit: cover; border-radius: 8px;"> </div> </div> <div class="nds-swiper-navigation" hidden> <div class="nds-swiper-buttons"> <button class="nds-btn nds-subtle nds-icon-only nds-oncolor nds-prev" aria-label="Previous slide"></button> <button class="nds-btn nds-subtle nds-icon-only nds-oncolor nds-next" aria-label="Next slide"></button> </div> <div class="nds-swiper-pagination"></div> </div> </div>

Responsive Multi-Slide

Display multiple slides at once with responsive breakpoints: 4 slides on large desktop, 3 on desktop, and 1 on mobile/tablet.

Card 1

Multi-slide example with responsive breakpoints.

Card 2

Resize the browser to see responsive behavior.

Card 3

Drag or use arrows to navigate.

Card 4

Native scroll-snap behavior.

Card 5

Full RTL/LTR support.

Card 6

Touch and keyboard navigation.

<div class="nds-swiper" slides-max="4" slides-mid="3" slides-min="1" peek="0"> <div class="nds-swiper-wrapper"> <div class="nds-swiper-slide"> <div class="nds-card nds-stroke nds-shadow"> <div class="nds-card-content"> <span class="nds-card-title">Card 1</span> <p class="nds-card-description">Multi-slide example with responsive breakpoints.</p> </div> </div> </div> <div class="nds-swiper-slide"> <div class="nds-card nds-stroke nds-shadow"> <div class="nds-card-content"> <span class="nds-card-title">Card 2</span> <p class="nds-card-description">Resize the browser to see responsive behavior.</p> </div> </div> </div> <div class="nds-swiper-slide"> <div class="nds-card nds-stroke nds-shadow"> <div class="nds-card-content"> <span class="nds-card-title">Card 3</span> <p class="nds-card-description">Drag or use arrows to navigate.</p> </div> </div> </div> <div class="nds-swiper-slide"> <div class="nds-card nds-stroke nds-shadow"> <div class="nds-card-content"> <span class="nds-card-title">Card 4</span> <p class="nds-card-description">Native scroll-snap behavior.</p> </div> </div> </div> <div class="nds-swiper-slide"> <div class="nds-card nds-stroke nds-shadow"> <div class="nds-card-content"> <span class="nds-card-title">Card 5</span> <p class="nds-card-description">Full RTL/LTR support.</p> </div> </div> </div> <div class="nds-swiper-slide"> <div class="nds-card nds-stroke nds-shadow"> <div class="nds-card-content"> <span class="nds-card-title">Card 6</span> <p class="nds-card-description">Touch and keyboard navigation.</p> </div> </div> </div> </div> <div class="nds-swiper-navigation" hidden> <div class="nds-swiper-buttons"> <button class="nds-btn nds-primary nds-icon-only nds-circle nds-md nds-prev" type="button" aria-label="Previous slide"></button> <button class="nds-btn nds-primary nds-icon-only nds-circle nds-md nds-next" type="button" aria-label="Next slide"></button> </div> <div class="nds-swiper-pagination"></div> </div> </div>

Peek Mode

Show partial next/previous slides to indicate more content. Use the peek attribute to set the visible amount in pixels.

Card 1

Peek mode shows partial adjacent slides.

Card 2

Users can see there's more content.

Card 3

This encourages scrolling/navigation.

Card 4

Configurable peek amount in pixels.

Card 5

Works with any slides-per-view.

Card 6

Last slide in the carousel.

<div class="nds-swiper" slides-max="3" slides-mid="2" slides-min="1" peek="40"> <div class="nds-swiper-wrapper"> <div class="nds-swiper-slide"> <div class="nds-card nds-stroke nds-shadow"> <div class="nds-card-content"> <span class="nds-card-title">Card 1</span> <p class="nds-card-description">Peek mode shows partial adjacent slides.</p> </div> </div> </div> <div class="nds-swiper-slide"> <div class="nds-card nds-stroke nds-shadow"> <div class="nds-card-content"> <span class="nds-card-title">Card 2</span> <p class="nds-card-description">Users can see there's more content.</p> </div> </div> </div> <div class="nds-swiper-slide"> <div class="nds-card nds-stroke nds-shadow"> <div class="nds-card-content"> <span class="nds-card-title">Card 3</span> <p class="nds-card-description">This encourages scrolling/navigation.</p> </div> </div> </div> <div class="nds-swiper-slide"> <div class="nds-card nds-stroke nds-shadow"> <div class="nds-card-content"> <span class="nds-card-title">Card 4</span> <p class="nds-card-description">Configurable peek amount in pixels.</p> </div> </div> </div> <div class="nds-swiper-slide"> <div class="nds-card nds-stroke nds-shadow"> <div class="nds-card-content"> <span class="nds-card-title">Card 5</span> <p class="nds-card-description">Works with any slides-per-view.</p> </div> </div> </div> <div class="nds-swiper-slide"> <div class="nds-card nds-stroke nds-shadow"> <div class="nds-card-content"> <span class="nds-card-title">Card 6</span> <p class="nds-card-description">Last slide in the carousel.</p> </div> </div> </div> </div> <div class="nds-swiper-navigation" hidden> <div class="nds-swiper-buttons"> <button class="nds-btn nds-primary nds-icon-only nds-circle nds-md nds-prev" type="button" aria-label="Previous slide"></button> <button class="nds-btn nds-primary nds-icon-only nds-circle nds-md nds-next" type="button" aria-label="Next slide"></button> </div> <div class="nds-swiper-pagination"></div> </div> </div>

Built-in Features

Auto-initialization

Every nds-swiper on the page initializes automatically on load with no setup code required.

Native Scroll-Snap

Slides snap into place using CSS scroll-snap, giving smooth drag-to-scroll on desktop and natural swipe gestures on touch devices.

Responsive Breakpoints

Three-tier slide counts (slides-max, slides-mid, slides-min) adjust the visible slides at 960px and 600px breakpoints.

Lazy Loading

Images with data-src or data-srcset load automatically as slides approach the viewport, reducing initial page weight.

Keyboard Navigation

Arrow keys navigate between slides, Home jumps to the first, and End to the last. All keys are direction-aware for RTL layouts.

Peek Preview

Set a peek value in pixels to reveal partial adjacent slides, signaling that more content is available.

Lazy Slide Reveal

Hero slides marked with hidden are revealed automatically on first visibility, deferring image decoding for off-screen slides until the carousel scrolls into view.

Programmatic Control

Access any swiper instance via element._ndsSwiper to call slideTo(), prev(), next(), or destroy().

Usage Guidelines

Best Practices

  • Use the swiper for horizontally browsable collections like featured services, image galleries, or card carousels where showing everything at once would overwhelm the layout
  • Use the hero variant (nds-hero) for full-width banner sliders with background images or gradient slides at the top of a page
  • Use data-src and data-srcset for lazy loading images rather than standard src to reduce initial page weight
  • Do not use swiper for content that should be visible all at once. Use Grid for static card layouts or Tabs for switchable content panels
  • Do not place interactive form controls inside slides. Keep slide content to display elements: text, images, cards, and links
  • Add peek="40" when the slide count exceeds the visible slots, giving users a visual cue that more content is available
  • Always include hidden on .nds-swiper-navigation: the navigation row ships hidden and JS reveals it only when there are multiple pages. The swiper container itself does not use hidden; a CSS ::after placeholder on .nds-swiper:not([data-nds-swiper-initialized]) reserves the navigation row height before init
  • Keep slide heights consistent within a swiper. Mix uneven heights and the tallest slide will define the row height for all others
  • Always include aria-label on navigation buttons with clear directional text like "Previous slide" and "Next slide"
  • For full-width section breakouts, place the swiper inside a nds-section-body nds-max-width container so it can span beyond the content padding

Modifier Classes

ClassApplied toDescription
nds-hero.nds-swiperFull-width single-slide hero mode with overlay navigation absolutely positioned at the bottom
nds-oncolor.nds-swiperAdjusts pagination bullets and navigation contrast for dark or image backgrounds
nds-center.nds-swiper-navigationCenters the bullets and pushes the prev/next buttons to the outer edges of the navigation row
nds-lg.nds-swiper-paginationLarge pagination bullets (16px). Default size when no modifier is applied
nds-md.nds-swiper-paginationMedium pagination bullets (12px)
nds-sm.nds-swiper-paginationSmall pagination bullets (8px)

Data Attributes

AttributeDescription
slides-max="3"Slides visible at large breakpoint (viewport >= 960px). Default: 1
slides-mid="2"Slides visible at medium breakpoint (600px to 959px). Default: 1
slides-min="1"Slides visible at small breakpoint (viewport < 600px). Default: 1
peek="40"Pixels of adjacent slides to reveal. Only applies when there are multiple pages. Default: 0
hiddenPlace on .nds-swiper-navigation (not the container). JS re-decides visibility on every breakpoint change: removes hidden when there are multiple pages, restores it when there is only one
data-nds-swiper-initializedSet by JS after init completes (true). Used as a CSS hook (the pre-init ::after height reservation is scoped to :not([data-nds-swiper-initialized])) and as a guard to skip already-initialized swipers during NDS.Swiper.init(). Removed by destroy()
data-swiper-peekToggled on .nds-swiper by JS when peek is active (peek > 0 and multiple pages exist). Activates the CSS calc(var(--peek) + var(--swiper-gap)) peek-width formula in _swiper.scss. Removed by destroy()

CSS Custom Properties

Set these on .nds-swiper (or .nds-bullet) to override the defaults. Resolved tokens like --swiper-gap, --swiper-peek, --swiper-slides, and --swiper-total are managed by the component and should not be set directly.

PropertyDefaultDescription
--gapvar(--spacing-xl)Gap between slides
--padding0Inline padding applied to the scroll wrapper. Inside .nds-max-width the default shifts to var(--nds-viewport-padding) so the swiper can bleed to the viewport edge while its content stays aligned
--swiper-bullet-defaultvar(--colors-neutral-200)Inactive pagination bullet color (light theme); shifts to neutral-700 in dark mode and to translucent white on hero/on-color backgrounds
--swiper-bullet-default-hoveredvar(--colors-neutral-300)Inactive bullet hover color (one step from default: neutral-300 light, neutral-600 dark)
--swiper-bullet-activevar(--colors-primary-600)Active pagination bullet color (light theme); shifts to green-600 in dark mode and to base white on hero/on-color backgrounds
--swiper-bullet-active-hoveredvar(--colors-primary-700)Active bullet hover color (one step darker: primary-700 light, green-700 dark)
--swiper-bullet-bordertransparentBorder color around the pagination bullets

JavaScript API

All nds-swiper elements initialize automatically. Access an instance via element._ndsSwiper.

// ── Access instance ── const swiper = document.querySelector('.nds-swiper')._ndsSwiper; // ── Navigation ── swiper.slideTo(2); // Scroll to slide at index 2 (animated) swiper.slideTo(0, false); // Jump to first slide (no animation) swiper.goTo(4); // Snap to a page-aligned index (clamped to bounds) swiper.prev(); // Go to previous page swiper.next(); // Go to next page // ── Boundary state (for CSS hooks) ── // The container exposes data-state as the user scrolls: // data-state="at-start" first page is showing // data-state="at-end" last page is showing // data-state="at-start at-end" only one page (no scroll possible) // Style with: .nds-swiper[data-state~="at-end"] { ... } // ── Cleanup ── swiper.destroy(); // Remove listeners, pagination, and reset state // ── Factory ── const el = document.querySelector('.my-swiper'); const instance = NDS.Swiper.create(el); // Create and initialize a new instance // ── Re-initialize all swipers ── NDS.Swiper.init(); // Finds and initializes all uninitialized .nds-swiper elements NDS.Swiper.reinit(); // Alias for init(), same function, provided for lifecycle symmetry
Last Modified Date: 28/06/2026 - 01:27 PM
Was this page useful?
60% of users said Yes from 2843 Feedbacks