DEV Community

hideckies
hideckies

Posted on • Originally published at blog.hdks.org

Modal Window in Svelte

Svelte is my favorite compiler for developing web apps.

Sometimes I try to use other tools such as Web frameworks like React and Angular, but I tend to use Svelte eventually since I like it very much.

In this post, I write about implementing Modal Window which I often use when creating websites and apps.

1. Create a new project

It's easy.

npx degit sveltejs/template modal-app
cd modal-app
npm install
Enter fullscreen mode Exit fullscreen mode

2. Edit App.svelte

In App.svelte, delete the default code and write a simple HTML element.

<!-- src/App.svelte -->
<button>Open Modal</button>
Enter fullscreen mode Exit fullscreen mode

3. Create Modal.svelte

Next, create Modal.svelte in the same hierarchy as App.svelte.

And add HTML elements and styling in it for the modal window.

<!-- src/Modal.svelte -->
<div id="background"></div>
<div id="modal">
    <p>This is a modal window.</p>
</div>

<style>
    #background {
        position: fixed;
        z-index: 1;
        top: 0;
        left: 0;
        width: 100vw;
        height: 100vh;
    }

    #modal {
        position: fixed;
        z-index: 2;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        background: #fff;
        filter: drop-shadow(0 0 20px #333);
    }
</style>
Enter fullscreen mode Exit fullscreen mode

<div id="modal">...</div> is the body of the modal window.

When a modal window is displayed, <div id="background"></div> provides a transparent background for closing the modal window when you click outsite the modal. In short, this is for detecting the mouse click.

3. Import Modal.svelte in App.svelte

Import the Modal.svelte in App.svelte and add the component to the bottom of <button....

<!-- src/App.svelte -->
<script>
    import Modal from './Modal.svelte';
</script>

<button>Open Modal</button>
<Modal />
Enter fullscreen mode Exit fullscreen mode

Then the page looks like this:

screenshot_1

4. Add a state variable and property.

Add the variable named isOpenModal in <script> tag.

Also add the property named isOpenModal in <Modal> element.

<!-- src/App.svelte -->
<script>
    import Modal from './Modal.svelte';

    let isOpenModal = false;
</script>

    <button>Open Modal</button>
    <Modal isOpenModal={isOpenModal} />
</script>
Enter fullscreen mode Exit fullscreen mode

In Modal.svelte, add the property named isOpenModal.

<!-- src/Modal.svelte -->
<script>
    export let isOpenModal;
</script>

<!-- ... -->
Enter fullscreen mode Exit fullscreen mode

Then you can use the state variable isOpenModal represents if it's opening or closing.

5. Switch Open/Close

Create the functions switch the state of isOpenModal and connect it to <button>.

<!-- src/App.svelte -->
<script>
    import Modal from './Modal.svelte';

    let isOpenModal = false;

    function openModal() {
        isOpenModal = true;
    }

    function closeModal() {
        isOpenModal = false;
    }
</script>

<button on:click={openModal}>Open Modal</button>
<Modal isOpenModal={isOpenModal} />
Enter fullscreen mode Exit fullscreen mode

The button will call the openModal function when clicked. (But it still doesn't work for now.)

Let's edit the Modal component to make this work.

<!-- src/Modal.svelte -->
<script>
    // ...
</script>

<div id="background" style="--display: {isOpenModal ? 'block' : 'none'};"></div>
<div id="modal" style="--display: {isOpenModal ? 'block' : 'none'};">
    <p>This is a modal window.</p>
</div>

<style>
    #background {
        display: var(--display);
        // ...
    }

    #modal {
        display: var(--display);
        // ...
    }
</style>
Enter fullscreen mode Exit fullscreen mode

Added the CSS Custom Properties to style props in each element.

Thanks to this, when isOpenModal is true, modal is displayed, and when it is false, modal is hidden.

But it still does not work correctly for now because we have not implemented the process of closing the modal yet.

Let's do it.

6. Dispathcer

createEventDispathcer helps pass data between parent and child components.

<!-- src/Modal.svelte -->
<script>
    import { createEventDispathcer } from 'svelte';

    export let isOpenModal;

    const dispatch = createEventDispathcer();

    function closeModal() {
        isModalOpen = false;
        dispatch('closeModal', { isOpenModal });
    }
</script>

<div id="background" style="--display: {isOpenModal ? 'block' : 'none'}" on:click={closeModal}></div>
<!-- ... -->
Enter fullscreen mode Exit fullscreen mode

In addition to dispatch, added on:click event in <div id="background"> element.

When you click outsite the modal, the modal is closed.

Finally, add closeModal function to <Modal ... /> in App.svelte.

<!-- src/App.svelte -->

<!-- ... -->

<Modal isOpenModal={isOpenModal} on:closeModal={closeModal} />
Enter fullscreen mode Exit fullscreen mode

Clicking the "Open Modal" button will display the modal, and clicking outside the modal will close it.

screenshot_2

7. Conclusion

This is the entire code.

<!-- src/App.svelte -->
<script>
    import Modal from './Modal.svelte';

    let isOpenModal = false;

    function openModal() {
        isOpenModal = true;
    }

    function closeModal() {
        isOpenModal = false;
    }
</script>

<button on:click={openModal}>Open Modal</button>
<Modal isOpenModal={isOpenModal} on:closeModal={closeModal} />
Enter fullscreen mode Exit fullscreen mode
<!-- src/Modal.svelte -->
<script>
    import { createEventDispatcher } from 'svelte';

    const dispatch = createEventDispatcher();

    export let isOpenModal;

    function closeModal() {
        isOpenModal = false;
        dispatch('closeModal', { isOpenModal });
    }
</script>

<div id="background" style="--display: {isOpenModal ? 'block' : 'none'};" on:click={closeModal}></div>
<div id="modal" style="--display: {isOpenModal ? 'block' : 'none'};">
    <p>This is a modal window.</p>
</div>

<style>
    #background {
        display: var(--display);
        position: fixed;
        z-index: 1;
        top: 0;
        left: 0;
        width: 100vw;
        height: 100vh;
    }

    #modal {
        display: var(--display);
        position: fixed;
        z-index: 2;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        background: #fff;
        filter: drop-shadow(0 0 20px #333);
    }
</style>
Enter fullscreen mode Exit fullscreen mode

Top comments (0)