@clayui/modal

ClayModal component

Usage no npm install needed!

<script type="module">
  import clayuiModal from 'https://cdn.skypack.dev/@clayui/modal';
</script>

README


title: 'Modal' description: 'A modal is a secondary window that communicates or provides an action inside the same process.' lexiconDefinition: 'https://liferay.design/lexicon/core-components/modals/' packageNpm: '@clayui/modal'

import {ClayModalHeaderExamples, Modal} from '$packages/clay-modal/docs/index';

You may want to compose your content and customize with your use cases or add your own components while still keeping the logic of a modal.

useModal hook

The useModal hook is required to create a Modal component in Clay, it is responsible for communicating with ClayModal and controlling states to make animations, this is necessary because Modal needs animation when opening and closing so we need to delay calls of the onClose so you can safely control Modal's visibility or do other things.

useModal returns a signature with observer and onClose:

  • observer - Observer is the communication channel that connects ClayModal with useModal.
  • onClose - Callback is called after Modal's close animation.
const {observer, onClose} = useModal({
    onClose: () => setVisible(false),
});
To avoid future problems, do not use the information or change the values ​​of `observer`, it is considered a bad practice.

To prevent Modal from closing before animation always use the onClose method returned by useModal.

<ClayModal.Footer
-   last={<ClayButton onClick={() => setVisible(false)}>{"Primary"}</ClayButton>}
+   last={<ClayButton onClick={onClose}>{"Primary"}</ClayButton>}
/>

Usage

useModal is a hook so it implies that you cannot use ClayModal directly in a class component. If you'd like to use it in a class component, try the recommended strategy below.

  • Wrap ClayModal and useModal in a function component.
const ModalWithDialog = ({visible, onClose, title, body}) => {
    const { observer, onClose: close } = useModal({
        onClose: onVisible,
    });

    if (!visible) {
        return;
    }

    return (
        <ClayModal
            observer={observer}
            spritemap={spritemap}
        >
            <ClayModal.Header>{title}</ClayModal.Header>
            <ClayModal.Body>
                {body}
            </ClayModal.Body>
            <ClayModal.Footer
                last={<ClayButton onClick={close}>{"Close"}</ClayButton>}
            />
        </ClayModal>
    );
};

// This is pseudocode
class Page extends Component {
    render() {
        return (
            <>
                <ModalWithDialog visible={this.state.visible} onClose={() => this.setVisible(false)} title={...} body={...} />
                <ClayButton displayType="primary" onClick={() => this.setVisible(true)}>
                    {"Open modal"}
                </ClayButton>
            <>
        );
    }
}

useModal may be lost if you raise the visible condition above the hook, if Modal happens to be unmounted at the same time as the component. Ideally the hook is not unmounted every time Modal is opened and closed.

Header

ClayModal.Header offers two different APIs for use by toggling the prop withTitle. By default(withTitle={true}), ClayModal.Header behaves like a high-level component. If you want to use the lower-level components in Header, all you need to do is set withTitle={false}.

Here is an example of both APIs:

Provider

When your application uses a lot of modals, you can use <ClayModalProvider /> to have only one open Modal on the screen and the component centered on your application, you can invoke the modal from the context through the API. It is not recommended to have multiple modals open at the same time.

Add in the project root:

<ClayModalProvider spritemap={spritemap}>
    <MyApp />
</ClayModalProvider>

In any part of your application you can invoke modal.

import {Context} from '@clayui/modal';
import ClayButton from '@clayui/button';

const MyApp = () => {
    const [state, dispatch] = useContext(Context);

    return (
        <ClayButton
            displayType="primary"
            onClick={() =>
                dispatch({
                    payload: {
                        body: <h1>{'Hello world!'}</h1>,
                        footer: [
                            ,
                            ,
                            <ClayButton key={3} onClick={state.onClose}>
                                {'Primary'}
                            </ClayButton>,
                        ],
                        header: 'Title',
                        size: 'lg',
                    },
                    type: 1,
                })
            }
        >
            {'Open modal'}
        </ClayButton>
    );
};

Provider contains two different states that you can control:

  • Close - 0
  • Open - 1

The context signature is similar to a useReducer, contains state and dispatch.

const [state, dispatch] = useContext(Context);

dispatch({payload: {...}, type: 1});

state returns all values that are passed to dispatch payload and you can pass body, footer, header, size, status and url to payload.