hyper-modal
hyper-modal copied to clipboard
Fully customizable and accessible react modal component
React hyper modal
Fully customizable and accessible modal react component
Welcome to the react hyper modal repository 😄 I want to introduce you to an awesome react component for displaying modal windows
Live demo
Check also the new stackable content feature!
Table of contents
- Installation
- Usage
- Properties
- Default properties
- Types
- Contributing
- License
Installation
You can use
or
package managers
$ npm i --save react-hyper-modal
or
$ yarn add react-hyper-modal
Usage
Controlled modal component
import React from 'react';
import HyperModal from 'react-hyper-modal';
...
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
isModalOpen: false,
};
}
...
openModal => this.setState({ isModalOpen: true });
closeModal => this.setState({ isModalOpen: false });
...
render() {
const { isModalOpen } = this.state;
return (
<HyperModal
isOpen={isModalOpen}
requestClose={this.closeModal}
>
Your awesome modal content
</HyperModal>
);
}
}
Uncontrolled modal component
import React from 'react';
import HyperModal from 'react-hyper-modal';
...
const MyComponent = () => {
return (
<HyperModal
renderOpenButton={(requestOpen) => {
return (
<button onClick={requestOpen}>Open uncontrolled modal</button>
);
}
/>
);
}
Stackable content example
To use stackable content you should use ModalStack component and children as function. Every child of ModalStack will represent a different layout.
import React from 'react';
import HyperModal, { ModalStack, ModalStackProps } from 'react-hyper-modal';
...
const Component = () => {
const [index, setIndex] = React.useState(0)
return (
<HyperModal
stackable
stackableIndex={index}
renderOpenButton={requestOpen => (
<button type="button" className={styles.button} onClick={requestOpen}>Open stackable modal</button>
)}
>
{(props: ModalStackProps) => (
<ModalStack {...props}> // !!! It's very important to provide props to ModalStack
<div style={{ color: 'red' }}>
<div>1</div>
<button onClick={() => setIndex(1)}>open nested</button>
<button onClick={() => props.handleClose()}>close</button>
</div>
<div>
<div>2</div>
<button onClick={() => setIndex(2)}>open nested</button>
<button onClick={() => setIndex(0)}>close nested</button>
<button>close</button>
</div>
<div>
<div>3</div>
<button onClick={() => setIndex(1)}>close nested</button>
<button onClick={() => props.handleClose()}>close</button>
</div>
</ModalStack>
)}
</HyperModal>
)
}
That's it! 🍰✨
Properties
You can find props types and default props below the table.
* - required for controlled modal component
| Props | Description |
|---|---|
| afterClose | callback that is called after closing |
| ariaEnabled | enable ARIA properties |
| ariaProps | custom ARIA properties |
| beforeClose | callback that is called before closing |
| childrenMode | describing if the modal content should be rendered as React Children |
| classes | overriding default modal class names |
| closeDebounceTimeout | time to close modal |
| closeIconPosition | position of close button |
| closeOnCloseIconClick | close the modal by pressing close button |
| closeOnDimmerClick | close the modal by pressing on dimmer |
| closeOnEscClick | close the modal by pressing ESC |
| dimmerEnabled | describing if the dimmer should be shown or not |
| isFullscreen | describing if the modal should be shown in full screen or not |
| isOpen * | describing if the modal should be shown or not |
| modalContentRef | reference to the modal content div |
| modalWrapperRef | reference to the modal wrapper div |
| portalMode | describing if the modal should be rendered in React Portal or not |
| portalNode | HTML node to create React Portal |
| position | setting the modal position |
| renderCloseIcon | callback for rendering custom close button |
| renderContent | callback for rendering custom modal content |
| renderOpenButton | callback or boolean describing if the modal should be uncontrolled component |
| requestClose * | callback to close the modal |
| stackable | make content stackable |
| stackableIndex | stack length |
| stackContentSettings | stackable content settings |
| unmountOnClose | describing if the modal should be unmounted when close |
Default properties
{
ariaEnabled: true,
ariaProps: {
'aria-describedby': 'hyper-modal-description',
'aria-labelledby': 'hyper-modal-title',
role: 'dialog',
},
disableScroll: true,
childrenMode: true,
closeDebounceTimeout: 0,
closeIconPosition: {
vertical: 'top' as const,
horizontal: 'right' as const,
},
closeOnCloseIconClick: true,
closeOnDimmerClick: true,
closeOnEscClick: true,
dimmerEnabled: true,
isFullscreen: false,
portalMode: false,
position: {
alignItems: 'center' as const,
justifyContent: 'center' as const,
},
stackable: false,
stackableIndex: 0,
stackContentSettings: {
widthRatio: 4,
topOffsetRatio: 2,
transition: 'all 0.3s ease',
opacityRatio: 0.2,
}
}
Types
type TModalPosition = 'flex-start' | 'center' | 'flex-end';
type THorizontalPosition = 'left' | 'center' | 'right';
type TVerticalPosition = 'top' | 'middle' | 'bottom';
interface IClassNamesProps {
closeIconClassName?: string;
contentClassName?: string;
dimmerClassName?: string;
portalWrapperClassName?: string;
wrapperClassName?: string;
}
interface IARIAProps {
'aria-describedby'?: string;
'aria-labelledby'?: string;
role?: string;
}
interface IPositionProps {
alignItems?: TModalPosition;
justifyContent?: TModalPosition;
}
interface ICloseIconPosition {
horizontal?: THorizontalPosition;
vertical?: TVerticalPosition;
}
interface IModalProps {
afterClose?: () => void;
ariaEnabled?: boolean;
ariaProps?: IARIAProps;
beforeClose?: () => void;
childrenMode?: boolean;
classes?: IClassNamesProps;
closeDebounceTimeout?: number;
closeIconPosition?: ICloseIconPosition;
closeOnCloseIconClick?: boolean;
closeOnDimmerClick?: boolean;
closeOnEscClick?: boolean;
dimmerEnabled?: boolean;
isFullscreen?: boolean;
isOpen: boolean;
modalContentRef?: React.RefObject<HTMLDivElement>;
modalWrapperRef?: React.RefObject<HTMLDivElement>;
portalMode?: boolean;
portalNode?: HTMLElement;
position?: IPositionProps;
renderCloseIcon?: () => JSX.Element | null | string;
renderContent?: () => JSX.Element | JSX.Element[] | null | string;
renderOpenButton?: boolean | ((requestOpen: () => void) => JSX.Element | string);
requestClose: () => void;
unmountOnClose?: boolean;
}
Contributing
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
Please make sure to update tests as appropriate.