Scroll More - National Design System

A general-purpose overflow wrapper that auto-detects its scroll axis, fades the edges of clipped content, and shows a sticky button to paginate through the rest.

Vertical Overflow

A constrained height exposes a faded bottom edge and a full-width show-more button. Each click advances the list by one page minus the fade distance.

  • Riyadh
  • Jeddah
  • Mecca
  • Medina
  • Dammam
  • Khobar
  • Taif
  • Tabuk
  • Abha
  • Buraydah
  • Khamis Mushait
  • Hail

Horizontal Overflow

A row that exceeds its container fades on both inline edges. The button spans full height with a vertically written label and scrolls one page per click.

Horizontal Card Track

A row of cards in a grid track that exceeds its container, producing a horizontal overflow, dual-edge fade, and a full-height show-more button beside the track.

Identity Verification

Verify your national identity and obtain digital certificates for government transactions

Passport Renewal

Renew your passport online with expedited processing and home delivery options

Birth Certificate Request

Request official birth certificates and family documentation online

Marriage Contract Registration

Register marriage contracts and obtain official marriage certificates

Driver's License Services

Apply for, renew, or update your driving license information

Vehicle Registration

Register new vehicles, transfer ownership, or renew your vehicle registration

Built-in Features

Auto-initialization

Activates on any .nds-scroll-more on the page. Overflow detection, scroll listeners, and button handlers attach automatically.

Axis Auto-detection

Measures content on both axes and picks vertical or horizontal based on which one overflows. No configuration attribute required.

Edge Fade Mask

Fades the scrollable edges to hint at hidden content. The fade adapts to start, middle, and end positions and adjusts for RTL horizontal scroll.

Item-aware Step

One full item from the previous page stays visible as an anchor on the next click, so users never lose their place when paging through long lists or card tracks.

Loop to Start

When the user reaches the end, the button flips its icon and the next click returns the scroll position to the start.

Reactive to Layout

A ResizeObserver on the content re-runs overflow detection when the container or its children change size, so the button appears and disappears as needed.

Free-scroll Friendly

Passive scroll listener throttled by requestAnimationFrame, with the maximum scroll range cached and refreshed only when layout changes, so touch and trackpad momentum scroll stay smooth.

Programmatic Control

Re-initialize, manually recheck overflow, or tear down listeners per element through NDS.ScrollMore.

Usage Guidelines

Best Practices

  • Use Scroll More when you need to fit a long list, chip row, or card track into a bounded area while preserving full access to every item
  • Set --scroll-max-height for vertical lists and --scroll-max-width for horizontal rows. Without a size limit the content will not overflow and the button will not appear
  • Use a single wrapper for either direction; the axis is auto-detected from whichever dimension overflows, so the same markup works for vertical lists and horizontal rows
  • Do not use Scroll More for navigational tabs. Use Tabs, which has its own overflow and active-tab tracking
  • Do not use Scroll More for nested menus or multi-level navigation. Use Drawer, which handles submenu open/close state
  • Do not use Scroll More when a "Show all" affordance is enough and pagination is not needed. Use Expandable Content instead
  • Keep the first child uniform in size when you expect item-aware paging. The step is computed from the first child; uneven sizes still work but the "one page at a time" feel is weaker
  • Set --scroll-gap when you want visible breathing room between the content and the show-more button. Pair with nds-divided for a hairline separator on top of the gap
  • If children have borders, outlines, or shadows that get clipped by the overflow container, apply inline padding to .nds-scroll-more-content to reserve breathing room

Modifier Classes

ClassDescription
nds-dividedRenders a hairline separator between the content and the show-more button when overflow is present. No child element required
nds-snapApplies CSS scroll-snap so each direct child's leading edge aligns with the scroll container. Good for card tracks and large items

Data Attributes

AttributeDescription
data-axisSet automatically by the JS on .nds-scroll-more. Values: vertical, horizontal. Removed when content does not overflow
data-stateManaged automatically. Tokens: has-more (overflow present), at-start (scroll position 0), at-end (scroll position max). Drives mask fade and button icon direction

CSS Custom Properties

PropertyDefaultDescription
--scroll-max-heightnoneMaximum block size of the wrapper. Drives vertical overflow
--scroll-max-widthnoneMaximum inline size of the wrapper. Drives horizontal overflow
--scroll-fade48pxLength of the edge fade gradient on the overflow side(s)
--scroll-gap0Gap between the content and the show-more button
--scroll-divider--divider-colorColor of the border between content and button

JavaScript API

The NDS.ScrollMore API exposes initialization and teardown hooks. For dynamically added markup, call NDS.ScrollMore.init() to activate the new instances.

// ── Initialize all instances on the page ───────────── // Called automatically on DOMContentLoaded; call again after // injecting new .nds-scroll-more markup. NDS.ScrollMore.init(); // ── Initialize a single element ────────────────────── // Idempotent: safe to call on an already-initialized wrapper. const wrapper = document.querySelector('.nds-scroll-more'); NDS.ScrollMore.create(wrapper); // alias: initElement // ── Recheck overflow after content changes ─────────── // The built-in ResizeObserver handles size changes, but if // you mutate the DOM (add/remove items) without resizing // the container, call this to refresh the state. NDS.ScrollMore.checkOverflow(wrapper); // ── Tear down a single instance ────────────────────── // Disconnects the ResizeObserver and clears cached refs. // Use before removing the element from the DOM. NDS.ScrollMore.destroy(wrapper); // ── Re-run init on all elements ────────────────────── // Alias for init(); useful after bulk DOM replacement. NDS.ScrollMore.reinit();
Was this page useful?
60% of users said Yes from 2843 Feedbacks