Skip to content

ScrollShadow ​

A scroll shadow is a scrolling box that says so. It fades whichever edge has content beyond it — and only that edge, so the top stays sharp until something has actually been scrolled away.

It is the scroller: it owns the overflow, so give it a height to scroll within and put the padding on it rather than on a wrapper.

ts
import { ScrollShadow } from "ropav";

A scroll shadow is the edge of the box saying there is more where that came from.

It fades whichever edge has content past it, and only that edge — so the top stays sharp until something has been scrolled away.

Nothing here is painted over the content. The fade is a mask, which is why it works over any background the box happens to sit on.

visibility
template
<ScrollShadow class="flex max-h-32 w-72 flex-col gap-3 p-4">
  <Typography>
    A scroll shadow is the edge of the box saying there is more where that came from.
  </Typography>
  <Typography>
    It fades whichever edge has content past it, and only that edge — so the top stays sharp until something has been scrolled away.
  </Typography>
  <Typography>
    Nothing here is painted over the content. The fade is a mask, which is why it works over any background the box happens to sit on.
  </Typography>
</ScrollShadow>

Scroll the box to watch the fades come and go. size is the depth of the fade in pixels, and offset is how far the content has to have moved before one appears at all.

Horizontally ​

orientation decides the axis and, with it, which two edges can fade.

Bridging the future

Today, 6:30 PM

Rendering without a virtual DOM

Tomorrow, 9:00 AM

Colour on the web

Tomorrow, 2:15 PM

Keyboards all the way down

Friday, 11:00 AM

scroll-shadow-horizontal.vue
vue
<script setup lang="ts">
import { Card, CardDescription, CardTitle, ScrollShadow } from "ropav";

const talks = [
  { time: "Today, 6:30 PM", title: "Bridging the future" },
  { time: "Tomorrow, 9:00 AM", title: "Rendering without a virtual DOM" },
  { time: "Tomorrow, 2:15 PM", title: "Colour on the web" },
  { time: "Friday, 11:00 AM", title: "Keyboards all the way down" },
];
</script>

<template>
  <Card class="frame">
    <ScrollShadow class="scroller" orientation="horizontal">
      <div class="track">
        <Card v-for="talk in talks" :key="talk.title" class="tile" variant="transparent">
          <CardTitle class="tile__title">{{ talk.title }}</CardTitle>
          <CardDescription class="tile__note">{{ talk.time }}</CardDescription>
        </Card>
      </div>
    </ScrollShadow>
  </Card>
</template>

<style scoped>
.frame {
  width: 100%;
  max-width: var(--rp-container-md);
  padding: 0;
}

.scroller {
  padding: calc(var(--rp-spacing) * 4);
}

.track {
  display: flex;
  width: max-content;
  gap: calc(var(--rp-spacing) * 4);
}

.tile {
  min-width: calc(var(--rp-spacing) * 44);
  padding: calc(var(--rp-spacing) * 4);
}

.tile .tile__title {
  font-size: var(--rp-text-sm);
  line-height: var(--rp-text-sm--line-height);
}

.tile .tile__note {
  font-size: var(--rp-text-xs);
  line-height: var(--rp-text-xs--line-height);
}
</style>

Saying which edges yourself ​

visibility is auto by default, which is the component watching its own overflow. Naming an edge — top, both, none — takes that over, for a box whose content is about to change and should not flicker while it does. on-visibility-change reports what automatic detection settled on, and is-enabled stops that detection running at all.

The fade is a mask ​

The edges are cut out of the box rather than painted over it, so the effect works over any background the box happens to sit on — a card, a surface, a photograph — without being told what is behind it.

That also means it applies to everything inside, which is worth knowing before putting an interactive control right at a fading edge.

API ​

PropTypeDefaultDescription
hideScrollBarbooleanfalse
isEnabledbooleantrueWhether automatic overflow detection is enabled.
offsetnumber0Scroll distance before a shadow appears, in pixels.
onVisibilityChange((visibility: ScrollShadowVisibility) => void)—Called when automatic detection reaches a different visibility state.
orientation"horizontal" | "vertical""vertical"Scroll axis.
sizenumber40Size of the fade, in pixels.
styleStyleValue—
variant"fade""fade"Visual treatment.
visibility"auto" | "both" | "top" | "bottom" | "left" | "right" | "none""auto"Automatic or controlled shadow visibility.

Slots: default.