State containers which provide an interface for listening and responding to window events in a scalable fashion.
yarn add @render-props/viewport
or npm i @render-props/viewport
Viewport
- Component which provides context from
ViewportOrientation
, andViewportScroll
- Component which provides context from
ViewportProvider
- A top-level
Viewport
component which stores the viewport state and provides it as context toViewportConsumer
components.
- A top-level
ViewportConsumer
- Receives context updates from
ViewportProvider
when the viewport state changes
- Receives context updates from
ViewportOrientation
- Provides context for
{width, height, aspect, orientation, screenOrientation}
while receiving{width, height, aspect}
fromViewportSize
parent. - Updates each time the window size or orientation changes.
- Provides context for
ViewportSize
- Provides context for
{width, height, aspect}
. - Updates each time the window size or orientation changes.
- Provides context for
ViewportQueries
- Provides context for
{inView, inViewX, inViewY, inFullView, inFullViewX, inFullViewY}
- Provides context for
ViewportScroll
- Provides context for
{scrollX, scrollY, scrollTo, distance, direction}
- Updates each time the scroll position changes
- Provides context for
God component which provides context from ViewportOrientation
, and ViewportScroll
import Viewport from '@render-props/viewport'
const ViewportLogger = props => {
return (
<Viewport>
{({
width,
height,
aspect,
orientation,
screenOrientation,
scrollX,
scrollY,
distance,
direction,
scrollTo
}) => (
<>
<div>
width: {width}
</div>
<div>
scrollY: {scrollY}
</div>
<div>
aspect: {aspect}
</div>
</>
)}
</Viewport>
)
}
This component takes no props
scrollTo
(x <integer>, [y <integer>], [options <object{duration <ms>, timing <function>}>])
- scrolls to the provided
x
,y
coordinates in the window. You can optionally animate this by providing an options object with a duration. By default the timing function is linear, but you could for example use this bezier-easing library: https://github.com/gre/bezier-easingconst bezierCurve = BezierEasing(0, 0, 1, 0.5); scrollTo(0, 250, {timing: bezierCurve}) const cubicIn = x => x * x * x scrollTo(0, 250, {timing: cubicIn, duration: 400})
- scrolls to the provided
Note: these are only provided if withCoords
is true
.
scrollX {integer}
- the current horizontal scroll position in px
scrollY {integer}
- the current vertical scroll position in px
direction {object {x <integer>, y <integer>}}
- the direction the window was just scrolled
1
=right
forx
,down
fory
-1
=left
forx
,up
fory
0
= had no direction
- the direction the window was just scrolled
distance {object {x <integer>, y <integer>}}
- the distance between the latest recorded scroll activity in the window and the previous scroll activity
width {integer}
- the
clientWidth
of thedocumentElement
- the
height {integer}
- the
clientHeight
of thedocumentElement
- the
aspect {float}
- the aspect ratio
(width / height = aspect)
- the aspect ratio
orientation {landscape|square|portrait}
- returns
landscape
whenwidth > height
,square
whenwidth == height
, andportrait
whenwidth < height
- returns
screenOrientation {null|landscape-primary|landscape-secondary|portrait-primary|portrait-secondary}
null
: when orientation.type is unavailable'landscape-primary'
: when the device is landscape oriented, e.g. a laptop andwidth > height
'landscape-secondary'
: when the device is portrait oriented, e.g. a phone andwidth > height
'portrait-primary'
: when the device is portrait oriented, e.g. a phone andwidth < height
'portrait-secondary'
: when the device is landscape oriented, e.g. a laptop andwidth < height
A top-level Viewport
component which stores the viewport state
and provides it as context to ViewportConsumer
components.
It is in the only component in this package that is a not a render-prop component.
It takes valid react elements as children.
There are several benefits to using the ViewportProvider
/ViewportConsumer
components rather than Viewport
alone. There is only one event
listener of each type in the Provider model - so O(1) state is being
throttled and consumed vs. O(n).
import {ViewportProvider} from '@render-props/viewport'
function AppViewportProvider (AppWithViewportConsumers) {
return (
<ViewportProvider>
{AppWithViewportConsumers}
</ViewportProvider>
)
}
withCoords {bool} {default: true}
: iffalse
, the component will providegetScroll
,getSize
, andgetAspect
functions as opposed to{scrollX, scrollY, width, height, aspect}
Receives context updates from ViewportProvider
when the
viewport state changes. You can configure this component to only listen to
size or scroll events by using the observe
propert. See below for more details.
import {ViewportConsumer, observe} from '@render-props/viewport'
function SomeComponent (props) {
// This consumer listens to all changes in the viewport
return (
<ViewportConsumer>
{({
width,
height,
aspect,
orientation,
screenOrientation,
scrollX,
scrollY,
scrollTo
}) => (
<div>
width: {width}
</div>
)}
</ViewportConsumer>
)
}
function ScrollingComponent (props) {
// This consumer only listens to changes in viewport scroll position
return (
<ViewportConsumer observe='scroll'>
{({scrollX}) => (
<div>
scrollX: {scrollX}
</div>
)}
</ViewportConsumer>
)
}
function SizeComponent (props) {
// This consumer only listens to size changes in the viewport
return (
<ViewportConsumer observe='size'>
{({width, height}) => (
<div>
width: {width}
</div>
)}
</ViewportConsumer>
)
}
observe {string|array<string>}
- Configures the consumer to only update on changes to size or scroll position.
By default this consumer listens to all updates.
import {ViewportConsumer} from '@render-props/viewport' /** * observe.scrollX: 0b0001, * observe.scrollY: 0b0010, * observe.scroll: 0b0011, * observe.width: 0b0100, * observe.height: 0b1000, * observe.size: 0b1100, * observe.any: 0b1111, */ // listens to scroll position changes <ViewportConsumer observe='scroll'/> // listens to width and scrollY changes <ViewportConsumer observe={['width', 'scrollY']}/> // listens to all changes <ViewportConsumer/>
- Configures the consumer to only update on changes to size or scroll position.
By default this consumer listens to all updates.
Also see Viewport props
- Provides context for
{width, height, aspect, orientation, screenOrientation}
while receiving{width, height, aspect}
fromViewportSize
parent. - Updates each time the window size or orientation changes.
import {ViewportOrientation} from '@render-props/viewport'
function ViewportOrientationState (props) {
return (
<ViewportOrientation>
{({
width,
height,
aspect,
orientation,
screenOrientation
}) => (
<div>
orientation: {orientation}
</div>
)}
</ViewportOrientation>
)
}
withCoords {bool} {default: true}
: iffalse
, the component will providegetSize
, andgetAspect
functions as opposed to{width, height, aspect}
width {integer}
- the
clientWidth
of thedocumentElement
- the
height {integer}
- the
clientHeight
of thedocumentElement
- the
aspect {float}
- the aspect ratio
(width / height = aspect)
- the aspect ratio
orientation {landscape|square|portrait}
- returns
landscape
whenwidth > height
,square
whenwidth == height
, andportrait
whenwidth < height
- returns
screenOrientation {null|landscape-primary|landscape-secondary|portrait-primary|portrait-secondary}
- returns
null
if orientation.type is unavailablelandscape-primary
: when the device is landscape oriented, e.g. a laptop andwidth > height
landscape-secondary
: when the device is portrait oriented, e.g. a phone andwidth > height
portrait-primary
: when the device is portrait oriented, e.g. a phone andwidth < height
portrait-secondary
: when the device is landscape oriented, e.g. a laptop andwidth < height
- returns
- Provides context for
{width, height, aspect}
. - Updates each time the window size or orientation changes.
import {ViewportSize} from '@render-props/viewport'
function ViewportSizeState (props) {
return (
<ViewportSize>
{({width, height, aspect}) => (
<div>
width: {width}
</div>
)}
</ViewportSize>
)
}
withCoords {bool} {default: true}
: iffalse
, the component will providegetSize
, andgetAspect
functions as opposed to{width, height, aspect}
width {integer}
- the
clientWidth
of thedocumentElement
- the
height {integer}
- the
clientHeight
of thedocumentElement
- the
aspect {float}
- the aspect ratio
(width / height = aspect)
- the aspect ratio
Provides context for {inView, inViewX, inViewY, inFullView, inFullViewX, inFullViewY}
import {ViewportQueries} from '@render-props/viewport'
function ViewportQueriesState (props) {
return (
<ViewportQueries>
{({width, height, aspect}) => (
<div>
width: {width}
</div>
)}
</ViewportQueries>
)
}
inView
(element <DOMNode>, leeway <number|object{top, right, bottom, left}>)
- returns
true
if@element
is partially or completely visible within the window bounds, give or take@leeway
- returns
inViewX
(element <DOMNode>, leeway <number|object{top, right, bottom, left}>)
- returns
true
if@element
is partially or completely visible horizontally within the window bounds, give or take@leeway
- returns
inViewY
(element <DOMNode>, leeway <number|object{top, right, bottom, left}>)
- returns
true
if@element
is partially or completely visible vertically within the window bounds, give or take@leeway
- returns
inFullView
(element <DOMNode>, leeway <number|object{top, right, bottom, left}>)
- returns
true
if@element
is completely visible within the window bounds, give or take@leeway
- returns
inFullViewX
(element <DOMNode>, leeway <number|object{top, right, bottom, left}>)
- returns
true
if@element
is completely visible horizontally within the window bounds, give or take@leeway
- returns
inFullViewY
(element <DOMNode>, leeway <number|object{top, right, bottom, left}>)
- returns
true
if@element
is completely visible vertically within the window bounds, give or take@leeway
- returns
- Provides context for
{scrollX, scrollY, scrollTo}
- Updates each time the scroll position changes
import {ViewportScroll} from '@render-props/viewport'
function ViewportScrollState (props) {
return (
<ViewportScroll>
{({scrollX, scrollY, scrollTo, direction, distance}) => (
<div>
scrollY: {scrollY}
</div>
)}
</ViewportScroll>
)
}
withCoords {bool} {default: true}
: iffalse
, the component will provide agetScroll
function as opposed to{scrollX, scrollY, width, height, aspect}
scrollTo
(x <integer>, [y <integer>], [options <object{duration <ms>, timing <function>}>])
- scrolls to the provided
x
,y
coordinates in the window. You can optionally animate this by providing an options object with a duration. By default the timing function is linear, but you could for example use this bezier-easing library: https://github.com/gre/bezier-easingconst bezierCurve = BezierEasing(0, 0, 1, 0.5); scrollTo(0, 250, {timing: bezierCurve}) const cubicIn = x => x * x * x scrollTo(0, 250, {timing: cubicIn, duration: 400})
- scrolls to the provided
Note: these are only provided if withCoords
is true
.
scrollX {integer}
- the current horizontal scroll position in px
scrollY {integer}
- the current vertical scroll position in px
direction {object {x <integer>, y <integer>}}
- the direction the window was just scrolled
1
=right
forx
,down
fory
-1
=left
forx
,up
fory
0
= had no direction
- the direction the window was just scrolled
distance {object {x <integer>, y <integer>}}
- the distance between the latest recorded scroll activity in the window and the previous scroll activity