You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

376 lines
13 KiB

9 months ago
  1. <!-- <HEADER> // IGNORE IT -->
  2. <p align="center">
  3. <img src="https://rawcdn.githack.com/popperjs/popper-core/8805a5d7599e14619c9e7ac19a3713285d8e5d7f/docs/src/images/popper-logo-outlined.svg" alt="Popper" height="300px"/>
  4. </p>
  5. <div align="center">
  6. <h1>Tooltip & Popover Positioning Engine</h1>
  7. </div>
  8. <p align="center">
  9. <a href="https://www.npmjs.com/package/@popperjs/core">
  10. <img src="https://img.shields.io/npm/v/@popperjs/core?style=for-the-badge" alt="npm version" />
  11. </a>
  12. <a href="https://www.npmjs.com/package/@popperjs/core">
  13. <img src="https://img.shields.io/endpoint?style=for-the-badge&url=https://runkit.io/fezvrasta/combined-npm-downloads/1.0.0?packages=popper.js,@popperjs/core" alt="npm downloads per month (popper.js + @popperjs/core)" />
  14. </a>
  15. <a href="https://rollingversions.com/popperjs/popper-core">
  16. <img src="https://img.shields.io/badge/Rolling%20Versions-Enabled-brightgreen?style=for-the-badge" alt="Rolling Versions" />
  17. </a>
  18. </p>
  19. <br />
  20. <!-- </HEADER> // NOW BEGINS THE README -->
  21. **Positioning tooltips and popovers is difficult. Popper is here to help!**
  22. Given an element, such as a button, and a tooltip element describing it, Popper
  23. will automatically put the tooltip in the right place near the button.
  24. It will position _any_ UI element that "pops out" from the flow of your document
  25. and floats near a target element. The most common example is a tooltip, but it
  26. also includes popovers, drop-downs, and more. All of these can be generically
  27. described as a "popper" element.
  28. ## Demo
  29. [![Popper visualized](https://i.imgur.com/F7qWsmV.jpg)](https://popper.js.org)
  30. ## Docs
  31. - [v2.x (latest)](https://popper.js.org/docs/v2/)
  32. - [v1.x](https://popper.js.org/docs/v1/)
  33. We've created a
  34. [Migration Guide](https://popper.js.org/docs/v2/migration-guide/) to help you
  35. migrate from Popper 1 to Popper 2.
  36. To contribute to the Popper website and documentation, please visit the
  37. [dedicated repository](https://github.com/popperjs/website).
  38. ## Why not use pure CSS?
  39. - **Clipping and overflow issues**: Pure CSS poppers will not be prevented from
  40. overflowing clipping boundaries, such as the viewport. It will get partially
  41. cut off or overflows if it's near the edge since there is no dynamic
  42. positioning logic. When using Popper, your popper will always be positioned in
  43. the right place without needing manual adjustments.
  44. - **No flipping**: CSS poppers will not flip to a different placement to fit
  45. better in view if necessary. While you can manually adjust for the main axis
  46. overflow, this feature cannot be achieved via CSS alone. Popper automatically
  47. flips the tooltip to make it fit in view as best as possible for the user.
  48. - **No virtual positioning**: CSS poppers cannot follow the mouse cursor or be
  49. used as a context menu. Popper allows you to position your tooltip relative to
  50. any coordinates you desire.
  51. - **Slower development cycle**: When pure CSS is used to position popper
  52. elements, the lack of dynamic positioning means they must be carefully placed
  53. to consider overflow on all screen sizes. In reusable component libraries,
  54. this means a developer can't just add the component anywhere on the page,
  55. because these issues need to be considered and adjusted for every time. With
  56. Popper, you can place your elements anywhere and they will be positioned
  57. correctly, without needing to consider different screen sizes, layouts, etc.
  58. This massively speeds up development time because this work is automatically
  59. offloaded to Popper.
  60. - **Lack of extensibility**: CSS poppers cannot be easily extended to fit any
  61. arbitrary use case you may need to adjust for. Popper is built with
  62. extensibility in mind.
  63. ## Why Popper?
  64. With the CSS drawbacks out of the way, we now move on to Popper in the
  65. JavaScript space itself.
  66. Naive JavaScript tooltip implementations usually have the following problems:
  67. - **Scrolling containers**: They don't ensure the tooltip stays with the
  68. reference element while scrolling when inside any number of scrolling
  69. containers.
  70. - **DOM context**: They often require the tooltip move outside of its original
  71. DOM context because they don't handle `offsetParent` contexts.
  72. - **Compatibility**: Popper handles an incredible number of edge cases regarding
  73. different browsers and environments (mobile viewports, RTL, scrollbars enabled
  74. or disabled, etc.). Popper is a popular and well-maintained library, so you
  75. can be confident positioning will work for your users on any device.
  76. - **Configurability**: They often lack advanced configurability to suit any
  77. possible use case.
  78. - **Size**: They are usually relatively large in size, or require an ancient
  79. jQuery dependency.
  80. - **Performance**: They often have runtime performance issues and update the
  81. tooltip position too slowly.
  82. **Popper solves all of these key problems in an elegant, performant manner.** It
  83. is a lightweight ~3 kB library that aims to provide a reliable and extensible
  84. positioning engine you can use to ensure all your popper elements are positioned
  85. in the right place.
  86. When you start writing your own popper implementation, you'll quickly run into
  87. all of the problems mentioned above. These widgets are incredibly common in our
  88. UIs; we've done the hard work figuring this out so you don't need to spend hours
  89. fixing and handling numerous edge cases that we already ran into while building
  90. the library!
  91. Popper is used in popular libraries like Bootstrap, Foundation, Material UI, and
  92. more. It's likely you've already used popper elements on the web positioned by
  93. Popper at some point in the past few years.
  94. Since we write UIs using powerful abstraction libraries such as React or Angular
  95. nowadays, you'll also be glad to know Popper can fully integrate with them and
  96. be a good citizen together with your other components. Check out `react-popper`
  97. for the official Popper wrapper for React.
  98. ## Installation
  99. ### 1. Package Manager
  100. ```bash
  101. # With npm
  102. npm i @popperjs/core
  103. # With Yarn
  104. yarn add @popperjs/core
  105. ```
  106. ### 2. CDN
  107. ```html
  108. <!-- Development version -->
  109. <script src="https://unpkg.com/@popperjs/core@2/dist/umd/popper.js"></script>
  110. <!-- Production version -->
  111. <script src="https://unpkg.com/@popperjs/core@2"></script>
  112. ```
  113. ### 3. Direct Download?
  114. Managing dependencies by "directly downloading" them and placing them into your
  115. source code is not recommended for a variety of reasons, including missing out
  116. on feat/fix updates easily. Please use a versioning management system like a CDN
  117. or npm/Yarn.
  118. ## Usage
  119. The most straightforward way to get started is to import Popper from the `unpkg`
  120. CDN, which includes all of its features. You can call the `Popper.createPopper`
  121. constructor to create new popper instances.
  122. Here is a complete example:
  123. ```html
  124. <!DOCTYPE html>
  125. <title>Popper example</title>
  126. <style>
  127. #tooltip {
  128. background-color: #333;
  129. color: white;
  130. padding: 5px 10px;
  131. border-radius: 4px;
  132. font-size: 13px;
  133. }
  134. </style>
  135. <button id="button" aria-describedby="tooltip">I'm a button</button>
  136. <div id="tooltip" role="tooltip">I'm a tooltip</div>
  137. <script src="https://unpkg.com/@popperjs/core@^2.0.0"></script>
  138. <script>
  139. const button = document.querySelector('#button');
  140. const tooltip = document.querySelector('#tooltip');
  141. // Pass the button, the tooltip, and some options, and Popper will do the
  142. // magic positioning for you:
  143. Popper.createPopper(button, tooltip, {
  144. placement: 'right',
  145. });
  146. </script>
  147. ```
  148. Visit the [tutorial](https://popper.js.org/docs/v2/tutorial/) for an example of
  149. how to build your own tooltip from scratch using Popper.
  150. ### Module bundlers
  151. You can import the `createPopper` constructor from the fully-featured file:
  152. ```js
  153. import { createPopper } from '@popperjs/core';
  154. const button = document.querySelector('#button');
  155. const tooltip = document.querySelector('#tooltip');
  156. // Pass the button, the tooltip, and some options, and Popper will do the
  157. // magic positioning for you:
  158. createPopper(button, tooltip, {
  159. placement: 'right',
  160. });
  161. ```
  162. All the modifiers listed in the docs menu will be enabled and "just work", so
  163. you don't need to think about setting Popper up. The size of Popper including
  164. all of its features is about 5 kB minzipped, but it may grow a bit in the
  165. future.
  166. #### Popper Lite (tree-shaking)
  167. If bundle size is important, you'll want to take advantage of tree-shaking. The
  168. library is built in a modular way to allow to import only the parts you really
  169. need.
  170. ```js
  171. import { createPopperLite as createPopper } from '@popperjs/core';
  172. ```
  173. The Lite version includes the most necessary modifiers that will compute the
  174. offsets of the popper, compute and add the positioning styles, and add event
  175. listeners. This is close in bundle size to pure CSS tooltip libraries, and
  176. behaves somewhat similarly.
  177. However, this does not include the features that makes Popper truly useful.
  178. The two most useful modifiers not included in Lite are `preventOverflow` and
  179. `flip`:
  180. ```js
  181. import {
  182. createPopperLite as createPopper,
  183. preventOverflow,
  184. flip,
  185. } from '@popperjs/core';
  186. const button = document.querySelector('#button');
  187. const tooltip = document.querySelector('#tooltip');
  188. createPopper(button, tooltip, {
  189. modifiers: [preventOverflow, flip],
  190. });
  191. ```
  192. As you make more poppers, you may be finding yourself needing other modifiers
  193. provided by the library.
  194. See [tree-shaking](https://popper.js.org/docs/v2/performance/#tree-shaking) for more
  195. information.
  196. ## Distribution targets
  197. Popper is distributed in 3 different versions, in 3 different file formats.
  198. The 3 file formats are:
  199. - `esm` (works with `import` syntax — **recommended**)
  200. - `umd` (works with `<script>` tags or RequireJS)
  201. - `cjs` (works with `require()` syntax)
  202. There are two different `esm` builds, one for bundler consumers (e.g. webpack,
  203. Rollup, etc..), which is located under `/lib`, and one for browsers with native
  204. support for ES Modules, under `/dist/esm`. The only difference within the two,
  205. is that the browser-compatible version doesn't make use of
  206. `process.env.NODE_ENV` to run development checks.
  207. The 3 versions are:
  208. - `popper`: includes all the modifiers (features) in one file (**default**);
  209. - `popper-lite`: includes only the minimum amount of modifiers to provide the
  210. basic functionality;
  211. - `popper-base`: doesn't include any modifier, you must import them separately;
  212. Below you can find the size of each version, minified and compressed with the
  213. [Brotli compression algorithm](https://medium.com/groww-engineering/enable-brotli-compression-in-webpack-with-fallback-to-gzip-397a57cf9fc6):
  214. <!-- Don't change the labels to use hyphens, it breaks, even when encoded -->
  215. ![](https://badge-size.now.sh/https://unpkg.com/@popperjs/core/dist/umd/popper.min.js?compression=brotli&label=popper)
  216. ![](https://badge-size.now.sh/https://unpkg.com/@popperjs/core/dist/umd/popper-lite.min.js?compression=brotli&label=popper%20lite)
  217. ![](https://badge-size.now.sh/https://unpkg.com/@popperjs/core/dist/umd/popper-base.min.js?compression=brotli&label=popper%20base)
  218. ## Hacking the library
  219. If you want to play with the library, implement new features, fix a bug you
  220. found, or simply experiment with it, this section is for you!
  221. First of all, make sure to have
  222. [Yarn installed](https://yarnpkg.com/lang/en/docs/install).
  223. Install the development dependencies:
  224. ```bash
  225. yarn install
  226. ```
  227. And run the development environment:
  228. ```bash
  229. yarn dev
  230. ```
  231. Then, simply open one the development server web page:
  232. ```bash
  233. # macOS and Linux
  234. open localhost:5000
  235. # Windows
  236. start localhost:5000
  237. ```
  238. From there, you can open any of the examples (`.html` files) to fiddle with
  239. them.
  240. Now any change you will made to the source code, will be automatically compiled,
  241. you just need to refresh the page.
  242. If the page is not working properly, try to go in _"Developer Tools >
  243. Application > Clear storage"_ and click on "_Clear site data_".
  244. To run the examples you need a browser with
  245. [JavaScript modules via script tag support](https://caniuse.com/#feat=es6-module).
  246. ## Test Suite
  247. Popper is currently tested with unit tests, and functional tests. Both of them
  248. are run by Jest.
  249. ### Unit Tests
  250. The unit tests use JSDOM to provide a primitive document object API, they are
  251. used to ensure the utility functions behave as expected in isolation.
  252. ### Functional Tests
  253. The functional tests run with Puppeteer, to take advantage of a complete browser
  254. environment. They are currently running on Chromium, and Firefox.
  255. You can run them with `yarn test:functional`. Set the `PUPPETEER_BROWSER`
  256. environment variable to `firefox` to run them on the Mozilla browser.
  257. The assertions are written in form of image snapshots, so that it's easy to
  258. assert for the correct Popper behavior without having to write a lot of offsets
  259. comparisons manually.
  260. You can mark a `*.test.js` file to run in the Puppeteer environment by
  261. prepending a `@jest-environment puppeteer` JSDoc comment to the interested file.
  262. Here's an example of a basic functional test:
  263. ```js
  264. /**
  265. * @jest-environment puppeteer
  266. * @flow
  267. */
  268. import { screenshot } from '../utils/puppeteer.js';
  269. it('should position the popper on the right', async () => {
  270. const page = await browser.newPage();
  271. await page.goto(`${TEST_URL}/basic.html`);
  272. expect(await screenshot(page)).toMatchImageSnapshot();
  273. });
  274. ```
  275. You can find the complete
  276. [`jest-puppeteer` documentation here](https://github.com/smooth-code/jest-puppeteer#api),
  277. and the
  278. [`jest-image-snapshot` documentation here](https://github.com/americanexpress/jest-image-snapshot#%EF%B8%8F-api).
  279. ## License
  280. MIT