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.
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.
<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
<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
| Prop | Type | Default | Description |
|---|---|---|---|
hideScrollBar | boolean | false | |
isEnabled | boolean | true | Whether automatic overflow detection is enabled. |
offset | number | 0 | Scroll 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. |
size | number | 40 | Size of the fade, in pixels. |
style | StyleValue | — | |
variant | "fade" | "fade" | Visual treatment. |
visibility | "auto" | "both" | "top" | "bottom" | "left" | "right" | "none" | "auto" | Automatic or controlled shadow visibility. |
Slots: default.