ToggleLayer
import { ToggleLayer } from 'react-laag';
ToggleLayer is the most important component of react-laag. As the name suggests, this component is used to toggle layers (between show and don't show). It assumes there are two key components at play:
- a trigger, which can be any html-element
- a layer, the element we want to toggle, can also be any html-element
position: relative;
react-laag expects you to style the scroll-parent where you want to contain your layer in position: relative
(or absolute
| fixed
). If your layer does not need to be contained, because the trigger scrolls with the rest of the page for instance, you don't have to do anything, because react-laag looks at the document.body
by default.
Render props
In order to give you as much control as possible, react-laag makes use of the render prop pattern; Instead of a normal react-element, react-laag expects you to pass in a function which in turn returns a react-element. To illustrate:
// Plain react-element...
<div />
// ...becomes
() => <div />
The cool thing about this is that react-laag provides you with tools, and you get to decide if and how to use them!
Controlled vs. uncontrolled
By default react-laag behaves uncontrolled. That means that some state is managed internally inside react-laag. Most of the time this works fine, but there are cases where more control is desirable. Fortunately, react-laag watches certain props and can tell if you want to manage parts of the state yourself.
const [isOpen, setOpen] = React.useState();
<ToggleLayer
// by setting this prop, react-laag knows
// you want control over this part of the state
isOpen={isOpen}
/>
Props
Render prop that should render the trigger. Minimal example:
<ToggleLayer
// rest of props go here
>
{({ triggerRef }) => <div ref={triggerRef}>Trigger</div>}
</ToggleLayer>
In order to calculate the layer's position, react-laag needs access to the trigger's dom-element. Assign triggerRef
to the ref prop when using a React-element or Component (make sure that you the ref
is forwarded with React.forwardRef
)
Describes whether the layer is open or closed
Shows the layer
Hides the layer
Toggles between show/hide
null
when the layer is closed.
When the layer is open, layerSide
describes on which side the layer is currently positioned relative to the trigger. When layerSide
is "center", it means that the layer is anchored "CENTER".
LayerSide = "top" | "right" | "bottom" | "left" | "center"
Render prop that should render the layer.
In some cases you can spread these layerProps
directly onto your component or element like so:
<div {...layerProps} />
But sometimes you want to add styles on top of the style-object react-laag provides. Such scenario's can be handled like this:
<div
ref={layerProps.ref}
style={{ ...layerProps.style, backgroundColor: 'blue'}}
/>
Determines whether we should render the layer or not. The reason for providing this prop, and not to ignore the renderLayer
prop entirely when isOpen === false
, is that you still have control over what to do when the layer is closed (ie. handling transitions / animations).
null
when the layer is closed.
When the layer is open, layerSide
describes on which side the layer is currently positioned relative to the trigger. When layerSide
is "center", it means that the layer is anchored "CENTER".
LayerSide = "top" | "right" | "bottom" | "left" | "center"
If you want to display an arrow-like element, which many tooltip-like components do, you can utilize the arrowStyle
. This style object gives the position of the center of the trigger, relative to the layer. How you style your arrow further is up to you. react-laag provides an <Arrow />
component which allows you to add an arrow element quick and easy, but you're free to use your own svg-element for instance, and calculate its rotation based on the layerSide
prop. Another possibility is to inject the positions into a styled-component and use a &::before{}
selector.
Useful if you want to style your layer according to the trigger's width for instance.
Useful if you want to close the layer, from within the layer itself. For instance, when a menu-item was clicked.
A quick example to illustrate all provided RenderLayerProp's:
<ToggleLayer
renderLayer={({ layerProps, isOpen, triggerRect, arrowStyle, close }) => {
if (isOpen) {
return (
<div
ref={layerProps.ref}
className="layer"
style={{
...layerProps.style,
width: triggerRect.width
}}
>
<div className="layer-arrow" style={arrowStyle} />
<button onClick={close}>close</button>
</div>
);
}
return null;
}}
// rest of props skipped for brevity
/>
A object containing configuration regarding the placement of the layer.
Tells react-laag which anchor (location of the layer) you prefer."CENTER" behaves a bit different compared to the rest of the anchors, in that it centers both horizontally and vertically, overlapping the trigger element.
possibleAnchors
has only effect when autoAdjust
is enabled. It describes which anchors should be considered when finding the best suitable anchor to fit on the screen.
Determines whether react-laag should find another anchor when the preferred one does not fit the current screen. When snapToAnchor
is set to false
, there will be a smooth 'sliding'-like effect from one anchor to the next.
Determines whether the layer can place itself between two anchors, creating a 'sliding'-effect when scrolling the page/element. WithsnapToAnchor
enabled, the layer will 'jump' from one anchor to the next one instantly.
Only has effect when autoAdjust
is enabled. Determines which side is preferred when the layer fits on both the left and right side of the trigger.
Only has effect when autoAdjust
is enabled. Determines which side is preferred when the layer fits on both the top and bottom side of the trigger.
Determines the distance in pixels between the layer and the trigger.
Determines the minimum margin in pixels between the layer and the scroll-containers (incl. viewport)
Determines the minimum margin in pixels between the arrow and the layers edges. Useful when you need to respect the layers border-radius.
Sometimes your layer needs a different width and / or height based on certain conditions, ie. on which side the layer is relative to the trigger-element. react-laag needs to anticipate these conditional dimensions on order to find the best suitable place to render the layer. Otherwise, react-laag will 'see' the layer's dimensions only after it has been re-positioned, which may result in an infinite loop of positional calculations.
{
// rest of 'placement' here...
layerDimensions: layerSide => ({
width: layerSide === "bottom" ? 200 : 100,
height: layerSide === "bottom" ? 100 : 200,
})
}
By default react-laag tries to render the layer within the closest scroll-container. But in some cases you want the layer to show outside its parent scroll-container. This is especially true for tooltip-like components. It's called 'fixed'-mode, because instead of positioning the layer absolute, relative to its parent, the layer gets positioned fixed against the viewport.
placement.autoAdjust
By setting the isOpen
prop, you are controlling when the layer should show or not. This also means that trying to call the open()
, close()
andtoggle()
functions from the children-props, will result in an error being thrown.
By passing onStyle
you get control over how the relevant elements are styled. This is an advanced feature, and should generally only be used when necessary. A reason to control the styles yourself, is when you run into performance issues because your layer/trigger is expensive to render, and you want to update the styles without causing React to re-render.
renderLayer
prop when things like the layer's anchor has changed.By setting this flag, react-laag will close the layer when a click has ocurred somewhere except the layer / trigger.
By using this prop, react-laag will notify you when a click has ocurred somewhere except the layer / trigger. Useful in combination with isOpen
.
The behavior depends on whether fixed is set to true
or false
:
In fixed mode, the layer will close when the trigger has fully / partially disappeared. In non-fixed mode, the layer will close when the layer has fully / partially disappeared.
By using this prop, react-laag will notify you when:
- the trigger has disappeared (fully / partially) in fixed mode
- the layer has disappeared (fully / partially) in non-fixed mode
Use this prop to inject a ResizeObserver polyfill for browsers that have no support out of the box.
Normally, react-laag renders the layers inside the closest scroll-parent. However, there might be use-cases where you want to control in which container the layers are rendered in. Since react-laag (in non-fixed mode) looks at the scrollTop
and scrollLeft
properties of the scroll-parent for positioning, it is advised to also put the container element inside the the same scroll-parent as the layer. It is possible to place the container element outside of the scroll-parent, but that will only work in 'fixed' mode.
document.getElementById
will suffice.<div className="scroll-container">
<div className="tooltip-container"></div>
<p>
Your content here...
<ToggleLayer
container={() => document.querySelector(".tooltip-container")}
/>
</p>
</div>
window
This prop is only useful if you're rendering react-laag within a different window context from where your JavaScript is running; for example, an iframe or a shadow-root.