- Let users know when there’s more content to see in an `overflow` container, in case their device hides scrollbars. - Uses [Intersection Observer](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver) for performance and accuracy –
npm install react-overflow-indicator- Let users know when there’s more content to see in an overflow container, in
case their device hides scrollbars.
- Uses
Intersection Observer
for performance and accuracy – no listening for scroll or resize events.
- Flexible: render any style of indicator you want (shadows, arrows, messages,
etc.) wherever you want, using any styling solution.
Some examples: shadows, fades, icons… | ||
|---|---|---|
Install:
``console`
$ yarn add react-overflow-indicator
Import:
`js`
import Overflow from 'react-overflow-indicator';
Render indicators automatically using inside of:
`jsx`
Render an element or put your content directly here…
…or, use the onStateChange prop to react to overflow however you like:
`jsx
const [canScroll, setCanScroll] = useState(false);
return (
<>
Render an element or put your content directly here…
{canScroll ? '👇' : '🌈'}
>
);
`
The overflow state provider. At a minimum it must contain an element, otherwise it will do nothing.
`jsx`
Your element(s) here!
As with any standard element, its height must be limited in some way in order
for it to actually scroll. Apply that style as you would any other element, with
style or className:
`jsx`
Usage with styled-components:
`jsx
const MyContainer = styled(Overflow)
max-height: 500px;;`
Any remaining props beyond those documented below will be passed along to the
underlying DOM element. Use this to pass className, style, or any other
native attribute.
#### Props
| Name | Type | Default | Description | |
|---|---|---|---|---|
| children | Node | Elements to render inside the outer container. This should include an | ||
| onStateChange | Function | Callback that receives the latest overflow state and an object of refs, if you’d | ||
| tolerance | One of… Number String | 0 | Distance (number of pixels or CSS length unit like 1em | |
Wrapper for content to render inside the scrollable viewport. This element will
grow to whatever size it needs to hold its content, and will cause the parent
viewport element to overflow. It must be rendered inside an
ancestor.
Although you can style this element directly by passing additional props like
className and style, it’s preferable to include styling on your own element
inside instead – otherwise you risk interfering with the
styles this component needs to function.
#### Props
| Name | Type | Default | Description | |
|---|---|---|---|---|
| children | Node | Content to render inside the scrollable viewport. | ||
A helper component for rendering your custom indicator when the viewport is
scrollable in a particular direction (or any direction). Must be rendered inside
an ancestor.
You can provide a direction prop to indicate when scrolling is allowed in a
particular direction:
`jsx`
…or exclude it to indicate when scrolling is allowed in any direction:
`jsx`
This component will mount its children when scrolling is allowed in the
requested direction, and unmount them otherwise. If you’d rather remain mounted
(to allow transitions, for example), then render a function. It will be supplied
with a Boolean (if direction is supplied) or an object with up, left,right, and down properties:
`jsx`
{canScroll => (canScroll ? '🔽' : '✅')}
#### Props
| Name | Type | Default | Description | |
|---|---|---|---|---|
| children | One of… Node Function | Indicator to render when scrolling is allowed in the requested direction. If | ||
| direction | One of… 'up' 'down' 'left' 'right' | The scrollabe direction to watch for. If not supplied, the indicator will be | ||
This hook provides full access to the Overflow’s context containing its current
state and refs. While should be good enough for most
use cases, you can use this if you have other use cases in mind. Must be used
inside an ancestor.
Returns an object like:
`js`
{
state: {
canScroll: {
up: Boolean,
left: Boolean,
right: Boolean,
down: Boolean
}
},
dispatch: Function,
tolerance: Number | String,
refs: {
viewport: Object
}
}
`jsx`
{(canScroll, refs) => (
type="button"
onClick={() => {
refs.viewport.current.scrollBy({
top: refs.viewport.current.clientHeight,
behavior: 'smooth'
});
}}
style={{ position: 'absolute', right: 10, bottom: 10 }}
>
{canScroll ? '⏬' : '✅'}
)}
Instead of the traditional method of listening for scroll and resize events,
this uses the more performant
Intersection Observer API.
Here, an IntersectionObserver watches each of the 4 sides of the viewport
element to see when the scrollable content extends past that edge.
When rendered, you’ll see a structure similar to this:
``
(Optional)
Finally, your scrollable content here…
That seems like a lot! But each one serves a purpose – various CSS and DOM
behaviors make this surprisingly difficult to implement otherwise.
From the top down:
- The element with data-scrollable-wrapper contains everything. If you want toheight
insert some indicator overlay (like shadows, an arrow, a floating message),
they should usually be children of this element so that they’ll be siblings of
the scrollable viewport and thus will remain in their positions instead of
scrolling away. When you define a or max-height to define thedata-scrollable-viewport
scrollable viewport size, it will be on this element.
- The element with is the one with overflow: auto.data-scrollable-wrapper
It will match the size of its parent (the ). Anydata-scrollable-content
indicators you render will usually be siblings of this element.
- The element with contains your content. It will growdata-scrollable-viewport
to whatever size it needs and potentially cause the data-scrollable-tolerance
element to overflow.
- The element with will optionally be inserted iftolerance` value; in that case, this element will be
you use a nonzero
observed instead of the content element.