Home

Awesome

<scroll-shadow> element

npm version bundle size (minified and gzipped)

A small web component to enhance scrollable elements with dynamic scroll indicators.

Installation

npm install scroll-shadow-element

Import the module as part of your app bundle, or with a script tag.

import 'scroll-shadow-element'
<script type="module" src="./node_modules/scroll-shadow-element/dist/index.js"></script>
<details><summary>Or load from a CDN like unpkg</summary>
<!-- unpkg CDN -->
<script type="module" src="https://unpkg.com/scroll-shadow-element"></script>

<!-- Skypack CDN -->
<script type="module" src="https://cdn.skypack.dev/scroll-shadow-element"></script>

<!-- Skypack CDN (minified) -->
<script type="module" src="https://cdn.skypack.dev/scroll-shadow-element?min"></script>
</details>

Usage

Wrap any element for dynamically added scroll indicators. For example:

<scroll-shadow>
  <nav>Long navigation…</nav>
</scroll-shadow>

Note: When wrapping a non-scrollable <table> element, then its first <tbody> will be used.

Configuration

You can change the default appearance with CSS.

Default

scroll-shadow {
  display: inline-block;
  --scroll-shadow-size: 14;
  --scroll-shadow-top: radial-gradient(farthest-side at 50% 0%, #0003, #0000);
  --scroll-shadow-bottom: radial-gradient(farthest-side at 50% 100%, #0003, #0000);
  --scroll-shadow-left: radial-gradient(farthest-side at 0%, #0003, #0000);
  --scroll-shadow-right: radial-gradient(farthest-side at 100%, #0003, #0000);
}

Example: dark mode

@media (prefers-color-scheme: dark) {
  scroll-shadow {
    --scroll-shadow-top: radial-gradient(farthest-side at 50% 0%, #fff3, #0000);
    --scroll-shadow-bottom: radial-gradient(farthest-side at 50% 100%, #fff3, #0000);
    --scroll-shadow-left: radial-gradient(farthest-side at 0%, #fff3, #0000);
    --scroll-shadow-right: radial-gradient(farthest-side at 100%, #fff3, #0000);
  }
}

CSS custom properties

PropertyDescriptionSyntax
--scroll-shadow-sizeSets the maximum size of the scroll indicators<integer>
--scroll-shadow-topControls the appearance of the top scroll indicatornone | <image>
--scroll-shadow-bottomControls the appearance of the bottom scroll indicatornone | <image>
--scroll-shadow-leftControls the appearance of the left scroll indicatornone | <image>
--scroll-shadow-rightControls the appearance of the right scroll indicatornone | <image>

Browser support

scroll-shadow-element works in all major browsers: all browsers that support Custom Elements, Resize Observer and the min() CSS function (Chrome/Edge 79+, Safari 13.1+, iOS Safari 13.4+, Firefox 75+). In older browsers, the element just won’t add scroll indicators.

The package is written with ES6 syntax. If you need to support older browsers, you can configure your bundler to compile it to ES5 syntax.

Using with Jest

{
  "jest": {
    "moduleNameMapper": {
      "^scroll-shadow-element$": "jest-transform-stub"
    }
  }
}

Jest doesn’t fully support ES modules: Depending on your configuration, you might see SyntaxError: Unexpected token 'export' along with a few hints in the error output. Jest’s "moduleNameMapper" option can be used to stub the module out. You can use any empty module, or jest-transform-stub.

Pure CSS alternative

<scroll-shadow> is inspired by Lea Verou’s great pure CSS scrolling shadows technique with background-attachment: local.

The main motivation to create a custom element was to find a solution to have the shadows above the content and independent of the element’s background. If you don’t have these requirements, the pure CSS technique might work for you too.

Since July 2023, it is possible to achieve the same with CSS scroll-driven animations (see also "Proper" Scrolling Shadows and Scroll shadows with animation-timeline). At the time of writing, browser support for scroll-driven animations is limited: e.g. it won’t work in Safari and Firefox. With <scroll-shadow>, scroll indicators can be applied declaratively in all major browsers, and the web component might get updated in the future to use ScrollTimeline.

Development

License

Distributed under the terms of the MIT license. See LICENSE for details.