Skip to content

Commit 6442387

Browse files
nikmilsonclaydiffrient
authored andcommitted
[changed] use object className and overlayClassName prop to override the default content and overlay classes;
use bodyOpenClassName to override body class name when modal opened
1 parent c184ddf commit 6442387

File tree

4 files changed

+79
-21
lines changed

4 files changed

+79
-21
lines changed

README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,26 @@ you can pass `className` and `overlayClassName` props to the Modal. If you do
8585
this then none of the default styles will apply and you will have full control
8686
over styling via CSS.
8787

88+
If you want to override default content and overlay classes you can pass object
89+
with three required properties: `base`, `afterOpen`, `beforeClose`.
90+
91+
```jsx
92+
<Modal
93+
...
94+
className={{
95+
base: 'myClass',
96+
afterOpen: 'myClass_after-open',
97+
beforeClose: 'myClass_before-close'
98+
}}
99+
overlayClassName={{
100+
base: 'myOverlayClass',
101+
afterOpen: 'myOverlayClass_after-open',
102+
beforeClose: 'myOverlayClass_before-close'
103+
}}
104+
...
105+
>
106+
```
107+
88108
You can also pass a `portalClassName` to change the wrapper's class (*ReactModalPortal*).
89109
This doesn't affect styling as no styles are applied to this element by default.
90110

@@ -115,6 +135,7 @@ function getParent() {
115135
### Body class
116136
When the modal is opened a `ReactModal__Body--open` class is added to the `body` tag.
117137
You can use this to remove scrolling on the the body while the modal is open.
138+
You can also pass a `bodyOpenClassName` to change the default class.
118139

119140
```CSS
120141
/* Remove scroll on the body when react-modal is open */

specs/Modal.spec.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,32 @@ describe('Modal', () => {
175175
expect(modal.portal.overlay.className.indexOf('myOverlayClass')).toNotEqual(-1);
176176
});
177177

178+
it('overrides the default content classes when a custom object className is used', () => {
179+
const modal = renderModal({
180+
isOpen: true,
181+
className: {
182+
base: 'myClass',
183+
afterOpen: 'myClass_after-open',
184+
beforeClose: 'myClass_before-close'
185+
}
186+
});
187+
expect(modal.portal.content.className).toEqual('myClass myClass_after-open');
188+
unmountModal();
189+
});
190+
191+
it('overrides the default overlay classes when a custom object overlayClassName is used', () => {
192+
const modal = renderModal({
193+
isOpen: true,
194+
overlayClassName: {
195+
base: 'myOverlayClass',
196+
afterOpen: 'myOverlayClass_after-open',
197+
beforeClose: 'myOverlayClass_before-close'
198+
}
199+
});
200+
expect(modal.portal.overlay.className).toEqual('myOverlayClass myOverlayClass_after-open');
201+
unmountModal();
202+
});
203+
178204
it('overrides the default styles when a custom classname is used', () => {
179205
const modal = renderModal({ ...getDefaultProps(), className: 'myClass' });
180206
expect(modal.portal.content.style.top).toEqual('');

src/components/Modal.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export default class Modal extends Component {
2121
overlay: React.PropTypes.object
2222
}),
2323
portalClassName: React.PropTypes.string,
24+
bodyOpenClassName: React.PropTypes.string,
2425
/**
2526
* A function that returns the appElement that will be aria-hidden
2627
* when the modal is open. The function should return a DOMElement or
@@ -41,6 +42,7 @@ export default class Modal extends Component {
4142
static defaultProps = {
4243
isOpen: false,
4344
portalClassName: 'ReactModalPortal',
45+
bodyOpenClassName: 'ReactModal__Body--open',
4446
ariaHideApp: true,
4547
closeTimeoutMS: 0,
4648
shouldCloseOnOverlayClick: true,
@@ -125,14 +127,14 @@ export default class Modal extends Component {
125127
ReactDOM.unmountComponentAtNode(this.node);
126128
const parent = getParentElement(this.props.parentSelector);
127129
parent.removeChild(this.node);
128-
elementClass(document.body).remove('ReactModal__Body--open');
130+
elementClass(document.body).remove(this.props.bodyOpenClassName);
129131
}
130132

131133
renderPortal (props) {
132134
if (props.isOpen) {
133-
elementClass(document.body).add('ReactModal__Body--open');
135+
elementClass(document.body).add(this.props.bodyOpenClassName);
134136
} else {
135-
elementClass(document.body).remove('ReactModal__Body--open');
137+
elementClass(document.body).remove(this.props.bodyOpenClassName);
136138
}
137139

138140
if (props.ariaHideApp) {

src/components/ModalPortal.js

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,8 @@ import {
1010

1111
// so that our CSS is statically analyzable
1212
const CLASS_NAMES = {
13-
overlay: {
14-
base: 'ReactModal__Overlay',
15-
afterOpen: 'ReactModal__Overlay--after-open',
16-
beforeClose: 'ReactModal__Overlay--before-close'
17-
},
18-
content: {
19-
base: 'ReactModal__Content',
20-
afterOpen: 'ReactModal__Content--after-open',
21-
beforeClose: 'ReactModal__Content--before-close'
22-
}
13+
overlay: 'ReactModal__Overlay',
14+
content: 'ReactModal__Content'
2315
};
2416

2517
export default class ModalPortal extends Component {
@@ -29,8 +21,22 @@ export default class ModalPortal extends Component {
2921
closeTimeoutMS: PropTypes.number,
3022
shouldCloseOnOverlayClick: PropTypes.bool,
3123
onRequestClose: PropTypes.func,
32-
className: PropTypes.string,
33-
overlayClassName: PropTypes.string,
24+
className: PropTypes.oneOfType([
25+
PropTypes.string,
26+
PropTypes.shape({
27+
base: PropTypes.string.isRequired,
28+
afterOpen: PropTypes.string.isRequired,
29+
beforeClose: PropTypes.string.isRequired
30+
})
31+
]),
32+
overlayClassName: PropTypes.oneOfType([
33+
PropTypes.string,
34+
PropTypes.shape({
35+
base: PropTypes.string.isRequired,
36+
afterOpen: PropTypes.string.isRequired,
37+
beforeClose: PropTypes.string.isRequired
38+
})
39+
]),
3440
defaultStyles: PropTypes.shape({
3541
content: PropTypes.object,
3642
overlay: PropTypes.object
@@ -191,12 +197,15 @@ export default class ModalPortal extends Component {
191197
}
192198

193199
buildClassName (which, additional) {
194-
let className = CLASS_NAMES[which].base;
195-
if (this.state.afterOpen) { className += ` ${CLASS_NAMES[which].afterOpen}`; }
196-
if (this.state.beforeClose) {
197-
className += ` ${CLASS_NAMES[which].beforeClose}`;
198-
}
199-
return additional ? `${className} ${additional}` : className;
200+
const classNames = (typeof additional === 'object') ? additional : {
201+
base: CLASS_NAMES[which],
202+
afterOpen: `${CLASS_NAMES[which]}--after-open`,
203+
beforeClose: `${CLASS_NAMES[which]}--before-close`
204+
};
205+
let className = classNames.base;
206+
if (this.state.afterOpen) { className += ` ${classNames.afterOpen}`; }
207+
if (this.state.beforeClose) { className += ` ${classNames.beforeClose}`; }
208+
return (typeof additional === 'string' && additional) ? `${className} ${additional}` : className;
200209
}
201210

202211
render () {

0 commit comments

Comments
 (0)