1 | ## React Popper
|
2 |
|
3 | [![Build Status](https://travis-ci.org/FezVrasta/react-popper.svg?branch=master)](https://travis-ci.org/FezVrasta/react-popper)
|
4 | [![npm version](https://img.shields.io/npm/v/react-popper.svg)](https://www.npmjs.com/package/react-popper)
|
5 | [![npm downloads](https://img.shields.io/npm/dm/react-popper.svg)](https://www.npmjs.com/package/react-popper)
|
6 | [![Dependency Status](https://david-dm.org/souporserious/react-popper.svg)](https://david-dm.org/souporserious/react-popper)
|
7 | [![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)](https://github.com/prettier/prettier)
|
8 | [![Get support or discuss](https://img.shields.io/badge/chat-on_spectrum-6833F9.svg?logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyBpZD0iTGl2ZWxsb18xIiBkYXRhLW5hbWU9IkxpdmVsbG8gMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgMTAgOCI%2BPGRlZnM%2BPHN0eWxlPi5jbHMtMXtmaWxsOiNmZmY7fTwvc3R5bGU%2BPC9kZWZzPjx0aXRsZT5zcGVjdHJ1bTwvdGl0bGU%2BPHBhdGggY2xhc3M9ImNscy0xIiBkPSJNNSwwQy40MiwwLDAsLjYzLDAsMy4zNGMwLDEuODQuMTksMi43MiwxLjc0LDMuMWgwVjcuNThhLjQ0LjQ0LDAsMCwwLC42OC4zNUw0LjM1LDYuNjlINWM0LjU4LDAsNS0uNjMsNS0zLjM1UzkuNTgsMCw1LDBaTTIuODMsNC4xOGEuNjMuNjMsMCwxLDEsLjY1LS42M0EuNjQuNjQsMCwwLDEsMi44Myw0LjE4Wk01LDQuMThhLjYzLjYzLDAsMSwxLC42NS0uNjNBLjY0LjY0LDAsMCwxLDUsNC4xOFptMi4xNywwYS42My42MywwLDEsMSwuNjUtLjYzQS42NC42NCwwLDAsMSw3LjE3LDQuMThaIi8%2BPC9zdmc%2B)](https://spectrum.chat/popper-js/react-popper)
|
9 |
|
10 | React wrapper around [Popper.js](https://popper.js.org).
|
11 |
|
12 | ## Install
|
13 |
|
14 | Via package managers:
|
15 |
|
16 | ```bash
|
17 | npm install react-popper@next --save
|
18 | # or
|
19 | yarn add react-popper@next
|
20 | ```
|
21 |
|
22 | Via `script` tag (UMD library exposed as `ReactPopper`):
|
23 |
|
24 | ```html
|
25 | <script src="https://unpkg.com/react-popper/dist/index.umd.js"></script>
|
26 | ```
|
27 |
|
28 | ## Usage
|
29 |
|
30 | > Using `react-popper@0.x`? You can find its documentation [clicking here](https://github.com/souporserious/react-popper/tree/v0.x)
|
31 |
|
32 | Example:
|
33 |
|
34 | ```jsx
|
35 | import { Manager, Reference, Popper } from 'react-popper';
|
36 |
|
37 | const Example = () => (
|
38 | <Manager>
|
39 | <Reference>
|
40 | {({ ref }) => (
|
41 | <button type="button" ref={ref}>
|
42 | Reference element
|
43 | </button>
|
44 | )}
|
45 | </Reference>
|
46 | <Popper placement="right">
|
47 | {({ ref, style, placement, arrowProps }) => (
|
48 | <div ref={ref} style={style} data-placement={placement}>
|
49 | Popper element
|
50 | <div ref={arrowProps.ref} style={arrowProps.style} />
|
51 | </div>
|
52 | )}
|
53 | </Popper>
|
54 | </Manager>
|
55 | );
|
56 | ```
|
57 |
|
58 | `react-popper` makes use of a React pattern called **"render prop"**, if you are not
|
59 | familiar with it, please read more [on the official React documentation](https://reactjs.org/docs/render-props.html).
|
60 |
|
61 | > Using React <=15 or Preact? The components created with them don't support to return
|
62 | [fragments](https://reactjs.org/docs/fragments.html), this means that you will need to
|
63 | wrap `<Reference />` and `<Popper />` into a single, common, `<div />` to make `react-popper` work.
|
64 |
|
65 | ### API documentation
|
66 |
|
67 | The `Manager` component is a simple wrapper that needs to surround all the other `react-popper` components in order
|
68 | to make them communicate with each others.
|
69 |
|
70 | The `Popper` component accepts the properties `children`, `placement`, `modifiers`, `eventsEnabled` and `positionFixed`.
|
71 |
|
72 | ```jsx
|
73 | <Popper
|
74 | innerRef={(node) => this.popperNode = node}
|
75 | placement="right"
|
76 | modifiers={{ preventOverflow: { enabled: false } }}
|
77 | eventsEnabled={true}
|
78 | positionFixed={false}
|
79 | >
|
80 | { props => [...] }
|
81 | </Popper>
|
82 | ```
|
83 |
|
84 | ##### `children`
|
85 |
|
86 | ```js
|
87 | children: ({|
|
88 | ref: (?HTMLElement) => void,
|
89 | style: { [string]: string | number },
|
90 | placement: ?Placement,
|
91 | outOfBoundaries: ?boolean,
|
92 | scheduleUpdate: () => void,
|
93 | arrowProps: {
|
94 | ref: (?HTMLElement) => void,
|
95 | style: { [string]: string | number },
|
96 | },
|
97 | |}) => Node
|
98 | ```
|
99 |
|
100 | A function (render prop) that takes as argument an object containing the properties
|
101 | `ref`, `style`, `placement`, and`arrowProps`.
|
102 |
|
103 | The first 3 properties are the `ref` property that is going to be used to retrieve the [React refs](https://reactjs.org/docs/refs-and-the-dom.html) of the **popper** element, the `style` property,
|
104 | which contains the CSS styles (React CSS properties) computed by Popper.js and needed to style
|
105 | the **popper** element so that it gets positioned in the desired way.
|
106 | These styles should be applied to your React component using the `style` prop or with any CSS-in-JS
|
107 | library of your choice.
|
108 |
|
109 | The `placement` property describes the placement of your popper after Popper.js has applied all the modifiers
|
110 | that may have flipped or altered the originally provided `placement` property. You can use this to alter the
|
111 | style of the popper and or of the arrow according to the definitive placement. For instance, you can use this
|
112 | property to orient the arrow to the right direction.
|
113 |
|
114 | `scheduleUpdate` is a function you can call to schedule a Popper.js position update. It will directly call the [Popper#scheduleUpdate](https://popper.js.org/popper-documentation.html#Popper.scheduleUpdate) method.
|
115 |
|
116 | The `arrowProps` argument is an object, containing a `style` and `ref` properties that are identical to the
|
117 | ones provided as first and second argument of `children`, but are relative to the **arrow** element rather than
|
118 | the popper. Use them to, accordingly, retrieve the ref of the **arrow** element and style it.
|
119 |
|
120 | ##### `innerRef`
|
121 | ```js
|
122 | innerRef?: (?HTMLElement) => void
|
123 | ```
|
124 |
|
125 | Function that can be used to obtain popper reference
|
126 |
|
127 | ##### `placement`
|
128 |
|
129 | ```js
|
130 | placement?: PopperJS$Placement;
|
131 | ```
|
132 |
|
133 | One of the accepted placement values listed in the [Popper.js documentation](https://popper.js.org/popper-documentation.html#Popper.placements).
|
134 | Your popper is going to be placed according to the value of this property.
|
135 | Defaults to `bottom`.
|
136 |
|
137 | ```js
|
138 | outOfBoundaries: ?boolean;
|
139 | ```
|
140 |
|
141 | A boolean that can be used to hide the popper element in case it's overflowing
|
142 | from its boundaries. [Read more](https://popper.js.org/popper-documentation.html#modifiers..hide).
|
143 |
|
144 | ##### `eventsEnabled`
|
145 |
|
146 | ```js
|
147 | eventsEnabled?: boolean;
|
148 | ```
|
149 |
|
150 | Tells `react-popper` to enable or disable the [Popper.js event listeners](https://popper.js.org/popper-documentation.html#Popper.Defaults.eventsEnabled). `true` by default.
|
151 |
|
152 | ##### `positionFixed`
|
153 |
|
154 | Set this property to `true` to tell Popper.js to use the `position: fixed` strategy
|
155 | to position the popper element. By default it's false, meaning that it will use the
|
156 | `position: absolute` strategy.
|
157 |
|
158 | ##### `modifiers`
|
159 |
|
160 | ```js
|
161 | modifiers?: PopperJS$Modifiers;
|
162 | ```
|
163 |
|
164 | An object containing custom settings for the [Popper.js modifiers](https://popper.js.org/popper-documentation.html#modifiers).
|
165 | You can use this property to override their settings or to inject your custom ones.
|
166 |
|
167 | ## Usage with `ReactDOM.createPortal`
|
168 |
|
169 | Popper.js is smart enough to work even if the **popper** and **reference** elements aren't
|
170 | in the same DOM context.
|
171 | This means that you can use [`ReactDOM.createPortal`](https://reactjs.org/docs/portals.html)
|
172 | (or any pre React 16 alternative) to move the popper component somewhere else in the DOM.
|
173 |
|
174 | This can be useful if you want to position a tooltip inside an `overflow: hidden` container
|
175 | that you want to make overflow. Please note that you can also try the `positionFixed` strategy
|
176 | to obtain a similar effect with less hassle.
|
177 |
|
178 | ```jsx
|
179 | import { Manager, Reference, Popper } from 'react-popper';
|
180 |
|
181 | const Example = () => (
|
182 | <Manager>
|
183 | <Reference>
|
184 | {({ ref }) => (
|
185 | <button type="button" ref={ref}>
|
186 | Reference
|
187 | </button>
|
188 | )}
|
189 | </Reference>
|
190 | {ReactDOM.createPortal(
|
191 | <Popper>
|
192 | {({ placement, ref, style }) => (
|
193 | <div ref={ref} style={style} data-placement={placement}>
|
194 | Popper
|
195 | </div>
|
196 | )}
|
197 | </Popper>,
|
198 | document.querySelector('#destination')
|
199 | )}
|
200 | </Manager>
|
201 | );
|
202 | ```
|
203 |
|
204 | ## Usage without a reference `HTMLElement`
|
205 |
|
206 | Whenever you need to position a popper based on some arbitrary coordinates, you can provide `Popper` with a `referenceElement` property that is going to be used in place of the `referenceProps.getRef` React ref.
|
207 |
|
208 | The `referenceElement` property must be an object with an interface compatible with an `HTMLElement` as described in the [Popper.js referenceObject documentation](https://popper.js.org/popper-documentation.html#referenceObject), this implies that you may also provide a real HTMLElement if needed.
|
209 |
|
210 | If `referenceElement` is defined, it will take precedence over any `referenceProps.ref` provided refs.
|
211 |
|
212 | ```jsx
|
213 | import { Popper } from 'react-popper';
|
214 |
|
215 | class VirtualReference {
|
216 | getBoundingClientRect() {
|
217 | return {
|
218 | top: 10,
|
219 | left: 10,
|
220 | bottom: 20,
|
221 | right: 100,
|
222 | width: 90,
|
223 | height: 10,
|
224 | };
|
225 | }
|
226 |
|
227 | get clientWidth() {
|
228 | return this.getBoundingClientRect().width;
|
229 | }
|
230 |
|
231 | get clientHeight() {
|
232 | return this.getBoundingClientRect().height;
|
233 | }
|
234 | }
|
235 |
|
236 | // This is going to create a virtual reference element
|
237 | // positioned 10px from top and left of the document
|
238 | // 90px wide and 10px high
|
239 | const virtualReferenceElement = new VirtualReference();
|
240 |
|
241 | // This popper will be positioned relatively to the
|
242 | // virtual reference element defined above
|
243 | const Example = () => (
|
244 | <Popper referenceElement={virtualReferenceElement}>
|
245 | {({ ref, style, placement, arrowProps }) => (
|
246 | <div ref={ref} style={style} data-placement={placement}>
|
247 | Popper element
|
248 | <div ref={arrowProps.ref} style={arrowProps.style} />
|
249 | </div>
|
250 | )}
|
251 | </Popper>
|
252 | );
|
253 | ```
|
254 |
|
255 | ## Flow and TypeScript types
|
256 |
|
257 | This library is built with Flow but it supports TypeScript as well.
|
258 |
|
259 | You can find the exported Flow types in `src/index.js`, and the
|
260 | TypeScript definitions in `typings/react-popper.d.ts`.
|
261 |
|
262 | ## Running Locally
|
263 |
|
264 | #### clone repo
|
265 |
|
266 | `git clone git@github.com:FezVrasta/react-popper.git`
|
267 |
|
268 | #### move into folder
|
269 |
|
270 | `cd ~/react-popper`
|
271 |
|
272 | #### install dependencies
|
273 |
|
274 | `npm install` or `yarn`
|
275 |
|
276 | #### run dev mode
|
277 |
|
278 | `npm run demo:dev` or `yarn demo:dev`
|
279 |
|
280 | #### open your browser and visit:
|
281 |
|
282 | `http://localhost:1234/`
|