Blog

Modal Window in Svelte

Web

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

2. Edit App.svelte

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

<!-- src/App.svelte -->
<button>Open Modal</button>

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>

<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 />

Then the page looks like this:

screenshot_1

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>

In Modal.svelte, add the property named isOpenModal.

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

<!-- ... -->

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} />

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>

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>
<!-- ... -->

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} />

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

screenshot_1

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} />


<!-- 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>