{"id":15312742,"url":"https://github.com/everweij/react-laag","last_synced_at":"2025-05-14T22:07:56.910Z","repository":{"id":41293817,"uuid":"213362743","full_name":"everweij/react-laag","owner":"everweij","description":"Hooks to build things like tooltips, dropdown menu's and popovers in React","archived":false,"fork":false,"pushed_at":"2024-03-20T06:59:52.000Z","size":4319,"stargazers_count":908,"open_issues_count":28,"forks_count":44,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-05-14T06:55:07.911Z","etag":null,"topics":["component","dropdown","hook","layers","popover","react","tooltip"],"latest_commit_sha":null,"homepage":"https://www.react-laag.com","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/everweij.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.MD","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-10-07T11:13:32.000Z","updated_at":"2025-04-26T21:15:38.000Z","dependencies_parsed_at":"2023-02-09T19:16:00.652Z","dependency_job_id":"4a1de606-b50e-4905-b095-5c78aa916359","html_url":"https://github.com/everweij/react-laag","commit_stats":{"total_commits":99,"total_committers":16,"mean_commits":6.1875,"dds":"0.24242424242424243","last_synced_commit":"400f215f32077a69fd0b44e400003818895ec265"},"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/everweij%2Freact-laag","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/everweij%2Freact-laag/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/everweij%2Freact-laag/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/everweij%2Freact-laag/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/everweij","download_url":"https://codeload.github.com/everweij/react-laag/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254123565,"owners_count":22018589,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["component","dropdown","hook","layers","popover","react","tooltip"],"created_at":"2024-10-01T08:38:26.540Z","updated_at":"2025-05-14T22:07:51.896Z","avatar_url":"https://github.com/everweij.png","language":"TypeScript","funding_links":[],"categories":["📦 Legacy \u0026 Inactive Projects","⚛️ React"],"sub_categories":["React-specific libs:"],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"./gh-logo.jpg\" width=\"260\" alt=\"react-laag\" /\u003e\n\u003c/p\u003e\n\n\u003ch3 align=\"center\" style=\"margin: 0;\"\u003e\n  Hooks for positioning tooltips \u0026 popovers\n\u003c/h3\u003e\n\n\u003cbr\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://www.npmjs.com/package/react-laag\" target=\"_blank\"\u003e\n    \u003cimg src=\"https://img.shields.io/npm/v/react-laag.svg?style=flat-square\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"http://www.typescriptlang.org/\" target=\"_blank\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/%3C%2F%3E-typescript-blue?style=flat-square\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://bundlephobia.com/result?p=react-laag\" target=\"_blank\"\u003e\n    \u003cimg src=\"https://flat.badgen.net/bundlephobia/minzip/react-laag\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://www.npmjs.com/package/react-laag\" target=\"_blank\"\u003e\n    \u003cimg src=\"https://flat.badgen.net/npm/dw/react-laag\" /\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n\u003cbr\u003e\n\nreact-laag provides a couple of tools to position UI elements such as tooltips and popovers with ease. It lets you focus on how your UI should look, feel and behave, by taking care of the heavy lifting such as complex calculations you would otherwise have to do yourself.\n\nTry it out for yourself [here](https://www.react-laag.com), or see some examples in our [storybook](https://storybook.react-laag.com).\n\n\u003e Click [here](https://v1.react-laag.com) for the v1 documentation, or read the [release-notes](https://github.com/everweij/react-laag/releases/tag/v2.0.0) for migrating to v2.\n\n### Features\n\n- 📦 Only 8kb minified \u0026 gzipped / tree-shakable / no dependencies\n- 🛠 We do the positioning, you do the rest. You maintain full control over the look and feel.\n- 🚀 Optimized for performance / no scroll lag whatsoever\n- 🏗 Comes with sensible defaults out of the box, but you can tweak things to your liking\n\n### Who is this library for?\n\nIf you are working on your own UI library / design-system, or just struggling with some complex auto-complete-select component, react-laag might be a match for you. The flexibility react-laag provides has a small price however: you still have to do some work regarding styling and animations yourself. This pattern is also referred to as _headless UI_.  \nSo, if you're looking for a full-fledged component out-of-the-box, I recommend to check out the wide range of excellent components already out there.\n\n---\n\n## Table of contents\n\n- [Getting started](#getting-started)\n  - [Installation](#installation)\n  - [Quick start](#quick-start)\n- [API Docs](#api-docs)\n  - [useLayer()](#uselayer)\n  - [useHover()](#usehover)\n  - [\\\u003cArrow /\u003e](#arrow-)\n  - [useMousePositionAsTrigger()](#usemousepositionastrigger)\n  - [mergeRefs()](#mergerefs)\n- [Concepts](#concepts)\n  - [Relative positioning](#relative-positioning)\n  - [Placement priority](#placement-priority)\n  - [Nesting](#nesting)\n  - [Animations](#animations)\n  - [z-index / container](#z-index-/-container)\n  - [Resize observer](#resize-observer)\n- [FAQ](#faq)\n- [Contributing](#contributing)\n\n\u003cbr\u003e\n\n## Getting started\n\n### Installation\n\n```bash\n# NPM\nnpm install react-laag\n\n# Yarn\nyarn add react-laag\n```\n\nThis library is build with TypeScript, so type-definitions are shipped out-of-the-box.\n\n### Quick start\n\nWe're only scratching the surface here, but here's a quick example to get some sense what this library feels like and how to get going.\n\n```jsx\nimport * React from \"react\";\nimport { useLayer, useHover, Arrow } from \"react-laag\";\n\nfunction Tooltip({ children, content }) {\n  const [isOver, hoverProps] = useHover();\n\n  const {\n    triggerProps,\n    layerProps,\n    arrowProps,\n    renderLayer\n  } = useLayer({\n    isOpen: isOver\n  });\n\n  return (\n    \u003c\u003e\n      \u003cspan {...triggerProps} {...hoverProps}\u003e\n        {children}\n      \u003c/span\u003e\n      {isOver \u0026\u0026\n        renderLayer(\n          \u003cdiv className=\"tooltip\" {...layerProps}\u003e\n            {content}\n            \u003cArrow {...arrowProps} /\u003e\n          \u003c/div\u003e\n        )}\n    \u003c/\u003e\n  );\n}\n```\n\nIn order to use this `\u003cTooltip /\u003e` component:\n\n```jsx\nconst someContent = (\n  \u003cdiv\u003e\n    When you hover \u003cTooltip content=\"I'm a tooltip!\"\u003ethis\u003c/Tooltip\u003e word, you\n    should see a tooltip\n  \u003c/div\u003e\n);\n```\n\n---\n\n## API docs\n\n### useLayer()\n\nThe most important hook for positioning and rendering the layer.\n\n```jsx\nimport { useLayer } from \"react-laag\";\n```\n\n```tsx\n(options: UseLayerOptions): UseLayerProps;\n```\n\n#### UseLayerOptions\n\n| name               | type                                                        | required | default        | description                                                                                                                                                                                                                                                                                                                                                                                    |\n| ------------------ | ----------------------------------------------------------- | -------- | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| isOpen             | `boolean`                                                   | ✔        |                | signals whether the layer is open or closed                                                                                                                                                                                                                                                                                                                                                    |\n| overflowContainer  | `boolean`                                                   |          | `true`         | should the layer be contained within the closest scroll-container (`false`), or is the layer allowed to overflow its closest scroll-container (`true`)?                                                                                                                                                                                                                                        |\n| placement          | `string`                                                    |          | `\"top-center\"` | preferred placement of the layer. One of: `\"top-center\"` / `\"top-start\"` / `\"top-end\"` / `\"left-start\"` / `\"left-center\"` / `\"left-end\"` / `\"right-start\"` / `\"right-center\"` / `\"right-end\"` / `\"bottom-start\"` / `\"bottom-center\"` / `\"bottom-end\"` / `\"center\"`                                                                                                                             |\n| possiblePlacements | `string[]`                                                  |          | all            | in case of `auto: true`, describes which placements are possible. Default are all placements.                                                                                                                                                                                                                                                                                                  |\n| preferX            | `\"left\" \\| \"right\"`                                         |          | `\"right\"`      | in case of `auto: true`, when both left and right sides are available, which one is preferred? Note: this option only has effect when `placement` is \"top-\\*\" or \"bottom-\\*\".                                                                                                                                                                                                                  |\n| preferY            | `\"top\" \\| \"bottom\"`                                         |          | `\"bottom\"`     | in case of `auto: true`, when both top and bottom sides are available, which one is preferred? Note: this option only has effect when `placement` is \"left-\\*\" or \"right-\\*\"                                                                                                                                                                                                                   |\n| auto               | `boolean`                                                   |          | `false`        | should we switch automatically to a placement that is more visible on the screen?                                                                                                                                                                                                                                                                                                              |\n| snap               | `boolean`                                                   |          | `false`        | in case of `auto: true`, should we stick to the possible placements (`true`), or should we gradually move between two placements (`false`)                                                                                                                                                                                                                                                     |\n| triggerOffset      | `number`                                                    |          | `0`            | distance in pixels between layer and trigger                                                                                                                                                                                                                                                                                                                                                   |\n| containerOffset    | `number`                                                    |          | `10`           | distance in pixels between layer and scroll-containers                                                                                                                                                                                                                                                                                                                                         |\n| arrowOffset        | `number`                                                    |          | `0`            | minimal distance between arrow and edges of layer and trigger                                                                                                                                                                                                                                                                                                                                  |\n| layerDimensions    | `(layerSide: LayerSide): { width: number, height: number }` |          |                | lets you anticipate on the dimensions of the layer. Useful when the dimensions of the layer differ per side, preventing an infinite loop of re-positioning                                                                                                                                                                                                                                     |\n| onDisappear        | `(type: \"partial\" \\| \"full\"): void`                         |          |                | gets called when the layer or trigger partially or fully disappears from the screen when the layer is open. If `overflowContainer` is set to true, it looks at the trigger element. If `overflowContainer` is set to false, it looks at the layer element.                                                                                                                                     |\n| onOutsideClick     | `(): void`                                                  |          |                | gets called when user clicks somewhere except the trigger or layer when the layer is open                                                                                                                                                                                                                                                                                                      |\n| onParentClose      | `(): void`                                                  |          |                | Useful when working with nested layers. It is used by the parent layer to signal child layers that their layers should close also.                                                                                                                                                                                                                                                             |\n| container          | `HTMLElement \\| (): HTMLElement \\| string`                  |          |                | Specify in which container (html-element) the layers should mount into when `overflowContainer` is set to true or when there's no scroll-container found. By default, in such cases the layers are mounted into a generated div#layers which gets attached to the body of the document. This prop accepts various values. When an string is passed, it is interpreted as the id of an element. |\n| trigger            | `object`                                                    |          |                | This prop let's you specify information about the trigger you don't know beforehand. This is typically for situations like context-clicks (right-mouse-clicks) and text-selection. By using this prop the returning `triggerProps` of this hook will have no effect.                                                                                                                           |\n|                    | `getBounds: () =\u003e ClientRect`                               |          |                | A callback function that returns the bounds of the trigger.                                                                                                                                                                                                                                                                                                                                    |\n|                    | `getParent?: () =\u003e HTMLElement`                             |          |                | A callback function that returns the parent element. This is optional but may be needed in cases where you'll want to prevent overflow of the layer. In other words, if you use the default option `overflowContainer: true`, this callback will have no effect. The returning element is used to position the layer relatively and to register event-listeners.                               |\n| environment        | `Window`                                                    | `window` |                | useful when working with i-frames for instance, when things like event-listeners should be attached to another context (environment).                                                                                                                                                                                                                                                          |\n| ResizeObserver     | `ResizeObserverClass`                                       |          |                | pass a polyfill when the browser does not support ResizeObserver out of the box                                                                                                                                                                                                                                                                                                                |\n\n#### UseLayerProps\n\n| name          | type                                     | required                              | description                                                                                        |\n| ------------- | ---------------------------------------- | ------------------------------------- | -------------------------------------------------------------------------------------------------- |\n| triggerProps  | `object`                                 | ✔ (unless the trigger-option is used) | Spread these props on the trigger-element                                                          |\n|               | `ref: () =\u003e void`                        |                                       | Obtains a reference to the trigger-element                                                         |\n| layerProps    | `object`                                 | ✔                                     | Spread these props on the layer-element                                                            |\n|               | `ref: () =\u003e void`                        |                                       | Obtains a reference to the layer-element                                                           |\n|               | `style: CSSProperties`                   |                                       | style-object containing positional styles                                                          |\n| arrowProps    | `object`                                 |                                       | Spread these props on the arrow-component                                                          |\n|               | `ref: () =\u003e void`                        |                                       | Obtains a reference to the arrow-element                                                           |\n|               | `style: CSSProperties`                   |                                       | style-object containing positional styles                                                          |\n|               | `layerSide: LayerSide`                   |                                       | let the arrow-component know in which direction it should point                                    |\n| renderLayer   | `(children: ReactNode) =\u003e ReactPortal`   |                                       | Render the layer inside this function. Essentially, this is a wrapper around `createPortal()`      |\n| layerSide     | `\"top\" \\| \"bottom\" \\| \"right\" \\| \"left\"` |                                       | The side the layer is currently on relative to the trigger                                         |\n| triggerBounds | `ClientRect \\| null`                     |                                       | Bounds of the trigger when `isOpen: true`. Useful when sizing the layer relatively to the trigger. |\n\n### useHover()\n\nUtility hook for managing hover behavior.\n\n```jsx\nimport { useHover } from \"react-laag\";\n```\n\n```tsx\n(options?: UseHoverOptions): [boolean, UseHoverProps, () =\u003e void];\n```\n\n**Example usage**\n\n```jsx\nconst [\n  isOver, // should we show the layer?\n  hoverProps, // spread these props to the trigger-element\n  close // optional callback to set `isOver` to `false`\n] = useHover({\n  delayEnter: 300, // wait 300ms before showing\n  delayLeave: 300, // wait 300ms before leaving\n  hideOnScroll: true // hide layer immediately when user starts scrolling\n});\n```\n\n#### UseHoverOptions\n\n| name         | type      | required | default | description                                         |\n| ------------ | --------- | -------- | ------- | --------------------------------------------------- |\n| delayEnter   | `number`  |          | `0`     | delay in ms                                         |\n| delayLeave   | `number`  |          | `0`     | delay in ms                                         |\n| hideOnScroll | `boolean` |          | `true`  | sets hovering to `false` when user starts scrolling |\n\n#### UseHoverProps\n\n| name         | type         |\n| ------------ | ------------ |\n| onMouseEnter | `() =\u003e void` |\n| onMouseLeave | `() =\u003e void` |\n| onTouchStart | `() =\u003e void` |\n| onTouchMove  | `() =\u003e void` |\n| onTouchEnd   | `() =\u003e void` |\n\n### \\\u003cArrow /\u003e\n\n```jsx\nimport { Arrow } from \"react-laag\";\n\n\u003cArrow\n  angle={45}\n  size={8}\n  roundness={0}\n  borderWidth={0}\n  borderColor=\"#000\"\n  backgroundColor=\"#FFF\"\n  layerSide=\"top\"\n/\u003e;\n```\n\n`\u003cArrow /\u003e` is basically just a regular svg-element, so it will accept all default svg-props as well\n\n#### ArrowProps\n\n| name            | type     | required | default   | description                                                                    |\n| --------------- | -------- | -------- | --------- | ------------------------------------------------------------------------------ |\n| angle           | `number` |          | `45`      | Angle of the triangle in degrees. A smaller angle means a more 'pointy' arrow. |\n| size            | `number` |          | `8`       | distance in pixels between point of triangle and layer.                        |\n| roundness       | `number` |          | `0`       | Roundness of the point of the arrow. Range between `0` and `1`.                |\n| borderWidth     | `number` |          | `0`       | Width of the border in pixels                                                  |\n| borderColor     | `string` |          | `\"black\"` | Color of the border                                                            |\n| backgroundColor | `string` |          | `\"white\"` | Color of the arrow                                                             |\n| layerSide       | `string` |          | `\"top\"`   | Determines where to arrow should point to                                      |\n\n### useMousePositionAsTrigger()\n\nUtility hook that lets you use the mouse-position as source of the trigger. This is useful in scenarios like context-menus.\n\n```jsx\nimport { useMousePositionAsTrigger } from \"react-laag\";\n```\n\n```tsx\n(options?: UseMousePositionAsTriggerOptions): UseMousePositionAsTriggerProps;\n\ntype UseMousePositionAsTriggerProps = {\n  hasMousePosition: boolean;\n  resetMousePosition: () =\u003e void;\n  handleMouseEvent: (evt: MouseEvent) =\u003e void;\n  trigger: {\n    getBounds: () =\u003e ClientRect;\n    getParent?: () =\u003e HTMLElement;\n  };\n  parentRef: MutableRefObject;\n};\n```\n\n**Example usage**\n\n```jsx\nfunction ContextMenu() {\n  const {\n    hasMousePosition,\n    handleMouseEvent,\n    resetMousePosition,\n    trigger\n  } = useMousePositionAsTrigger();\n\n  const { layerProps, renderLayer } = useLayer({\n    isOpen: hasMousePosition,\n    onOutsideClick: resetMousePosition,\n    trigger\n  });\n\n  return (\n    \u003c\u003e\n      \u003cdiv onContextMenu={handleMouseEvent}\u003eRight-click to show the layer\u003c/div\u003e\n      {hasMousePosition \u0026\u0026 renderLayer(\u003cdiv\u003eLayer\u003c/div\u003e)}\n    \u003c/\u003e\n  );\n}\n```\n\nSee the [context-menu example](https://storybook.react-laag.com/?path=/docs/nested-menu-s--page) or [text-selection example](https://storybook.react-laag.com/?path=/docs/text-selection--page) for more info.\n\n#### UseMousePositionAsTriggerOptions\n\n| name           | type      | required | default | description                                              |\n| -------------- | --------- | -------- | ------- | -------------------------------------------------------- |\n| enabled        | `number`  |          | `true`  | Should the mouse-position currently be actively tracked? |\n| preventDefault | `boolean` |          | `true`  | Should `handleMouseEvent` preventDefault()?              |\n\n### mergeRefs()\n\nUtility function that lets you assign multiple references to a 'ref' prop.\n\n```jsx\nimport * as React from \"react\";\nimport { mergeRefs } from \"react-laag\";\n\nconst ref1 = React.useRef();\nconst ref2 = element =\u003e console.log(element);\n\n\u003cdiv ref={mergeRefs(ref1, ref2)} /\u003e;\n```\n\n---\n\n## Concepts\n\n### Relative positioning\n\nreact-laag allows you to use to methods or modes for positioning with help of the `overflowContainer` option in `useLayer()`. When using `overflowContainer: true`, which is the default behavior, the layer is mounted somewhere high in the document in its own container. In such a case, the position of the layer will be `fixed`, meaning that it will be positioned relative to the window.  \nOn the other hand, you can decide you don't want to overflow the container by setting `overflowContainer` to `false`. In this scenario the layer will be mounted right under the scroll-container.  \nSo, what do we mean by the term 'scroll-container' anyways? react-laag considers a scroll-container an element which has set the `overflow`, `overflow-x` or `overflow-y` style to one of `\"auto\"` or `\"scroll\"`. react-laag tries to find these scrollable-containers by traversing up the dom-tree, starting with the trigger-element. This way, the layer will be positioned relatively to the closest scroll-container. There's one catch though: it expects you to set the `position: relative` style on this scroll-container. If you accidentally forgot to set this style, react-laag will output a friendly warning in the console.\n\n### Placement priority\n\nThis usually is something you don't have to think about, but in some cases it may come in handy.  \nWhen setting the `auto` option to `true` in `useLayer()`, react-laag will create an priority-order under the hood. The preferred `placement` will always be on top of the list, meaning this placement will be tried first. To determine the placements after that, react-laag looks at the following things:\n\n- the preferred placement for determining the preferred direction / axis. When using `\"top-start\"` for instance, we can assume that although this exact placement may not fit, somewhere on top is still preferred. This direction / axis will have more priority over `preferX` / `preferY`.\n- `preferX` / `preferY` for determining priority on the **opposite** axis regarding the preferred placement.\n- The next placement in line must always be as close to the previous placement as possible.\n- placements which are not defined in `possiblePlacements` (all by default) are skipped\n\nLet's look at an example given placement `\"top-start\"` with a preferX of `\"right\"`:\n\n```\ntop-start -\u003e top-center -\u003e top-end -\u003e right-end -\u003e left-end -\u003e right-center -\u003e left-center -\u003e right-start -\u003e left-start -\u003e bottom-start -\u003e bottom-center -\u003e bottom-end\n```\n\nDuring rendering react-laag will given the list containing priorities...\n\n- try to find the first placement in line that fits the current screen / layout\n- if none fits, it will find the placement with the most visible surface\n\n### Nesting\n\nNesting multiple layer often occurs in large menus where items are grouped. If you're looking for an example of how to accomplish this, be sure to check out the [example](https://storybook.react-laag.com/?path=/docs/nested-menu-s--page) about nesting.\n\nThere are however some important things to consider. How do we for instance signal to the rest of the nested layers, that a layer higher up in the hierarchy has just closed? Fortunately, there's a special option for that in the `userLayer()` options: `onParentClose`. react-laag uses context under the hood to monitor which layers are related to each other. This has a couple of implications:\n\n- When a layer closes, it will signal child-layers below to close as well through `onParentClose`.\n- `onOutsideClick` only has effect on root-layer. react-laag has a kind of event-bubbling system under the hood to make sure that the root-layer doesn't close when some child-layer down below was clicked. When there was a solid click outside somewhere in the document, the root-layer will signal the rest of the layers to close as well.\n\n### Animations\n\nreact-laag doesn't do any animations for you. Why? Because we want to focus this library purely on positioning and there are a lot of libraries out there who do a far better job than react-laag could ever do.  \nSince `renderLayer` is just an abstraction over React's `createPortal` you can in theory use any form of animation you'd like.\nPersonally, I'm a big fan of [framer-motion](https://github.com/framer/motion), so I will show you a quick example to get started:\n\n```jsx\nimport { useLayer } from \"react-laag\";\nimport { motion, AnimatePresence } from \"framer-motion\";\n\nfunction AnimationExample() {\n  const [isOpen, setOpen] = React.useState(false);\n\n  const { renderLayer, triggerProps, layerProps } = useLayer({ isOpen });\n\n  return (\n    \u003c\u003e\n      \u003cbutton {...triggerProps} onClick={() =\u003e setOpen(!isOpen)}\u003e\n        Click me!\n      \u003c/button\u003e\n      {renderLayer(\n        \u003cAnimatePresence\u003e\n          {isOpen \u0026\u0026 (\n            \u003cmotion.div\n              {...layerProps}\n              initial={{ opacity: 0 }}\n              animate={{ opacity: 1 }}\n              exit={{ opacity: 0 }}\n            \u003e\n              Layer\n            \u003c/motion.div\u003e\n          )}\n        \u003c/AnimatePresence\u003e\n      )}\n    \u003c/\u003e\n  );\n}\n```\n\n### z-index / container\n\nBy design react-laag doesn't handle any z-indexes for you. There are too many different use-cases and scenarios possible for this library to manage. You are free to implement your own z-index strategy. However, there is a cheap fix that will probably fix 95% of your problems.  \nBy default, react-laag renders your layers in a container right under the document's body:\n\n```html\n\u003cbody\u003e\n  \u003c!-- React's entry --\u003e\n  \u003cdiv id=\"root\"\u003e\u003c/div\u003e\n\n  \u003c!-- By default all layers will be rendered here --\u003e\n  \u003cdiv id=\"layers\"\u003e\u003c/div\u003e\n\u003c/body\u003e\n```\n\nNow, nothing is stopping you to do this:\n\n```css\n#layers {\n  z-index: 1000;\n}\n```\n\nAll layers will now automatically inherit the z-index of this container.\n\nIf you want react-laag to mount the layers into another element, you have two options:\n\n- use the `container` option in `useLayer()`:\n\n```jsx\nconst {} = useLayer({\n  // pass in an id of the element\n  container: \"my-own-container-id\",\n\n  // pass in a callback returning an html-element\n  container: () =\u003e myContainer,\n\n  // pass in a html-element directly\n  container: myContainer\n});\n```\n\n- set the container globally with `setGlobalContainer()`:\n\n```jsx\n// somewhere in the root of your application\nimport { setGlobalContainer } from \"react-laag\";\n\n// works the same as the container-option above\nsetGlobalContainer(\"my-own-container-id\");\n```\n\n### Resize observer\n\nIf you want to take full advantage of react-laag's positioning change detection, make sure your target browser(s) support `ResizeObserver`. To get a detailed list which browsers support this feature consult [Can I use](https://caniuse.com/resizeobserver).\nAs of now, this sort of means all modern browsers except IE 11.\nIf you need to support IE 11 you can optionally provide your app with a [polyfill](https://github.com/que-etc/resize-observer-polyfill).\nIf you don't want to pollute the global context you can also pass in the polyfill via the option in `useLayer`:\n\n```jsx\nimport ResizeObserver from \"resize-observer-polyfill\";\nimport { useLayer } from \"react-laag\";\n\nuseLayer({ ResizeObserver });\n```\n\n## FAQ\n\n\u003cdetails\u003e\n  \u003csummary\u003eIs there support for accessability?\u003c/summary\u003e\n  \n  No, unfortunately not. There are two primary reasons:\n  - This library is primary focussed around positioning\n  - Accessability not my area of expertise\n\nI'm open to the idea in the future though. I would be happy to get some help with this!\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003eWhich browsers are supported?\u003c/summary\u003e\n  \n  react-laag works on all modern browsers. Is should also work in \u003e= IE 11, although this may require a polyfill for [stable-features](https://github.com/zloirock/core-js)\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003eWill this work with server-side-rendering?\u003c/summary\u003e\n  \n  Yes, each build a small tests gets run in other to test compatibility.\n\n\u003c/details\u003e\n\n## Contributing\n\nWant to contribute to react-laag? Your help is very much appreciated!\nPlease consult the [contribution guide](./CONTRIBUTING.MD) on how to get started.\n\n## License\n\nMIT © [everweij](https://github.com/everweij)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feverweij%2Freact-laag","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feverweij%2Freact-laag","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feverweij%2Freact-laag/lists"}