├── .babelrc
├── .eslintrc
├── .github
└── workflows
│ └── semgrep.yml
├── .gitignore
├── .npmignore
├── CHANGELOG.md
├── LICENSE
├── README.md
├── example
├── .gitignore
├── animated
│ ├── index.html
│ ├── script.js
│ └── styles.css
├── basic
│ ├── index.html
│ ├── script.js
│ └── styles.css
├── redux
│ ├── index.html
│ ├── script.js
│ └── styles.css
└── universal
│ ├── Application.js
│ ├── browser.js
│ ├── server.js
│ └── styles.css
├── karma.conf.js
├── package.json
├── src
├── Modal.js
└── index.js
└── test
├── .eslintrc
└── index.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["cf"],
3 | "plugins": []
4 | }
5 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | # vim: set ft=yaml:
2 | ---
3 | env:
4 | browser: true
5 | node: true
6 | plugins:
7 | - "cflint"
8 | rules:
9 | # Possible Errors
10 | no-reserved-keys: 2
11 | quotes:
12 | - 2
13 | - "single"
14 | # Best Practices
15 | block-scoped-var: 2
16 | default-case: 2
17 | guard-for-in: 2
18 | no-else-return: 2
19 | no-floating-decimal: 2
20 | no-self-compare: 2
21 | no-void: 2
22 | radix: 2
23 | ## Possible that this will switch to a "2" later
24 | wrap-iife: 2
25 | # Strict Mode
26 | global-strict:
27 | - 2
28 | - "always"
29 | # Variables
30 | no-catch-shadow: 2
31 | # Node.js
32 | handle-callback-err: 2
33 | # Stylistic Issues
34 | brace-style:
35 | - 1
36 | - "1tbs"
37 | camelcase: 0
38 | comma-style:
39 | - 2
40 | - "last"
41 | no-lonely-if: 2
42 | no-nested-ternary: 2
43 | no-underscore-dangle: 0
44 | quote-props:
45 | - 1
46 | - "as-needed"
47 | semi:
48 | - 2
49 | - "always"
50 | space-unary-ops: 2
51 |
--------------------------------------------------------------------------------
/.github/workflows/semgrep.yml:
--------------------------------------------------------------------------------
1 | on:
2 | pull_request: {}
3 | workflow_dispatch: {}
4 | push:
5 | branches:
6 | - main
7 | - master
8 | schedule:
9 | - cron: '0 0 * * *'
10 | name: Semgrep config
11 | jobs:
12 | semgrep:
13 | name: semgrep/ci
14 | runs-on: ubuntu-latest
15 | env:
16 | SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }}
17 | SEMGREP_URL: https://cloudflare.semgrep.dev
18 | SEMGREP_APP_URL: https://cloudflare.semgrep.dev
19 | SEMGREP_VERSION_CHECK_URL: https://cloudflare.semgrep.dev/api/check-version
20 | container:
21 | image: semgrep/semgrep
22 | steps:
23 | - uses: actions/checkout@v4
24 | - run: semgrep ci
25 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | *.log
3 | lib
4 | coverage
5 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | *.log
3 | src
4 | coverage
5 | test
6 | example
7 | karma.conf.js
8 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | ## v5.0.2
4 | - Fixing regression introduced in v5.0.1 that affected event propagation [#33](https://github.com/cloudflare/react-modal2/pull/33)
5 |
6 | ## v5.0.1
7 | - Prevent modal from closing when backdrop is partial target of click [#30](https://github.com/cloudflare/react-modal2/pull/30)
8 |
9 | ## v5.0.0
10 | - Version bump. No changes from v3.2.0.
11 |
12 | ## v4.0.0
13 | DEPRECATED. Do not use.
14 |
15 | ## v3.2.0
16 | - Replace string refs with callback refs [#19](https://github.com/cloudflare/react-modal2/pull/19)
17 | - Use `prop-types` package instead of `React.PropTypes` (React 15.5.0 compatibility)
18 |
19 | ## v3.1.0
20 | - Replace `React.createClass` with ES6 Class (React 15.0.0 compatibility)
21 |
22 | ## v3.0.2
23 | - Remove unnecessary `bind` on `keydown` handler [#10](https://github.com/cloudflare/react-modal2/pull/10)
24 |
25 | ## v3.0.1
26 | - Docs update only
27 |
28 | ## v3.0.0
29 | - Universal/Isomorphic modals
30 |
31 | ### BREAKING CHANGES
32 | - Removed `ReactModal2.setApplicationElement()`. You must now [override](https://github.com/cloudflare/react-modal2/blob/v3.0.1/README.md#accessibility) `React.getApplicationElement()` in your application.
33 |
34 | ## v2.0.0
35 | - Remove `ReactGateway` from automatically being included. This is an implementation detail that should be in your modal component.
36 | - Allows for alternatives other than `ReactGateway`
37 | - Allows wrapping `ReactModal` inside `ReactGateway`
38 |
39 | ## v1.0.2
40 | - Fix `styles` => `style`
41 |
42 | ## v1.0.1
43 | - Fix references
44 |
45 | ## v1.0.0
46 | - Initial version
47 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2015, CloudFlare, Inc.
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
5 |
6 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7 |
8 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
9 |
10 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
11 |
12 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
13 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # react-modal2
2 |
3 | > Simple modal component for React.
4 |
5 | - Unopionated
6 | - Stateless (dumb component)
7 | - Accessible
8 | - Universal/Isomorphic
9 | - Built via [reusable](https://github.com/cloudflare/react-gateway) [collection](https://github.com/cloudflare/a11y-focus-scope) of [modules](https://github.com/cloudflare/a11y-focus-store)
10 |
11 | ## Installation
12 |
13 | ```js
14 | $ npm install --save react-modal2
15 | ```
16 |
17 | ## Usage
18 |
19 | ReactModal2 tries to be as minimal as possible. This means it requires a little
20 | bit of setup, but gives you complete flexibility to do what you want.
21 |
22 | Let's start off with the actual API of ReactModal2:
23 |
24 | ```js
25 |
43 | ...
44 |
45 | ```
46 |
47 | If we use it like this it will simply render those two elements in the dom like
48 | this:
49 |
50 | ```html
51 |
52 |
...
53 |
54 | ```
55 |
56 | However, you likely want to render the modal somewhere else in the DOM (in most
57 | cases at the end of the `document.body`.
58 |
59 | For this there is a separate library called
60 | [React Gateway](https://github.com/cloudflare/react-gateway). You can use it
61 | like this:
62 |
63 | ```js
64 | import {
65 | Gateway,
66 | GatewayDest,
67 | GatewayProvider
68 | } from 'react-gateway';
69 | import ReactModal2 from 'react-modal2';
70 |
71 | class Application extends React.Component {
72 | render() {
73 | return (
74 |
75 |
203 | );
204 | }
205 | }
206 | ```
207 |
208 | ## Props
209 | | Name | Type | Description |
210 | | --- | --- | --- |
211 | | `onClose` | `Function` | **Required.** A callback to handle an event that is attempting to close the modal. |
212 | | `closeOnEsc` | `Boolean` | Should this modal call `onClose` when the `esc` key is pressed? |
213 | | `closeOnBackdropClick` | `Boolean` | Should this modal call `onClose` when the backdrop is clicked? |
214 | | `backdropClassName` | `String` | An optional `className` for the backdrop element. |
215 | | `modalClassName` | `String` | An optional `className` for the modal element. |
216 | | `backdropStyles` | `Object` | Optional `style` for the backdrop element. |
217 | | `modalStyles` | `Object` | Optional `style` for the modal element. |
218 |
219 |
220 |
221 | ## Accessibility
222 |
223 | One of ReactModal2's opinions is that modals should be as accessible as
224 | possible. It does much of the work for you, but there's one little thing you
225 | need to help it with.
226 |
227 | In order to "hide" your application from screenreaders while a modal is open
228 | you need to let ReactModal2 what the root element for your application is.
229 |
230 | > **Note:** The root element should not contain the `GatewayDest` or whereever
231 | > the modal is getting rendered. This will break all the things.
232 |
233 | ```js
234 | import ReactModal2 from 'react-modal2';
235 |
236 | ReactModal2.getApplicationElement = () => document.getElementById('application');
237 | ```
238 |
239 | ## FAQ
240 |
241 | #### How do I close the modal?
242 |
243 | ReactModal2 is designed to have no state, if you put it in the DOM then it will
244 | render. So if you don't want to show it then simply do not render it in your
245 | parent component. For this reason there is no `isOpen` property to pass.
246 |
--------------------------------------------------------------------------------
/example/.gitignore:
--------------------------------------------------------------------------------
1 | */bundle.js
2 |
--------------------------------------------------------------------------------
/example/animated/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ReactModal2 Example: Animated
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/example/animated/script.js:
--------------------------------------------------------------------------------
1 | import React, {PropTypes} from 'react';
2 | import {render} from 'react-dom';
3 | import {
4 | Gateway,
5 | GatewayDest,
6 | GatewayProvider
7 | } from 'react-gateway';
8 | import CSSTransitionGroup from 'react-addons-css-transition-group';
9 | import ReactModal2 from '../../src/index';
10 |
11 | class Modal extends React.Component {
12 | static propTypes = {
13 | isOpen: PropTypes.bool.isRequired,
14 | onClose: PropTypes.func.isRequired,
15 | closeOnEsc: PropTypes.bool,
16 | closeOnBackdropClick: PropTypes.bool
17 | };
18 |
19 | static defaultProps = {
20 | closeOnEsc: true,
21 | closeOnBackdropClick: true
22 | };
23 |
24 | handleClose() {
25 | this.props.onClose();
26 | }
27 |
28 | render() {
29 | return (
30 |
31 |
37 | {this.props.isOpen && (
38 |
46 | {this.props.children}
47 |
48 | )}
49 |
50 |
51 | );
52 | }
53 | }
54 |
55 | class Application extends React.Component {
56 | constructor() {
57 | super();
58 | }
59 |
60 | state = {
61 | isModalOpen: false
62 | };
63 |
64 | handleOpen() {
65 | this.setState({ isModalOpen: true });
66 | }
67 |
68 | handleClose() {
69 | this.setState({ isModalOpen: false });
70 | }
71 |
72 | render() {
73 | return (
74 |
75 |