Skip to content

Instantly share code, notes, and snippets.

@tbmreza
Last active April 4, 2020 15:04
Show Gist options
  • Save tbmreza/54c6cd585f0fc10849f025bfc62637b8 to your computer and use it in GitHub Desktop.
Save tbmreza/54c6cd585f0fc10849f025bfc62637b8 to your computer and use it in GitHub Desktop.
Svelte modal component that can be drawn on top of another.
<script>
export let display;
import ModalInternals from "./ModalInternals.svelte";
let closeModal = false;
const handleClose = () => {
display = false;
};
</script>
{#if display}
<ModalInternals on:close={handleClose} {closeModal}>
<slot />
</ModalInternals>
{/if}
<script>
import Modal from "./Modal.svelte";
let showFirst = true;
let showAnother = false;
let showLast = false;
function handleClickFirst() {
showAnother = true;
}
function handleClickAnother() {
showLast = true;
}
function handleClickLast() {
showLast = false;
}
</script>
<Modal bind:display={showFirst}>
<button on:click={handleClickFirst}>Show another modal</button>
</Modal>
<Modal bind:display={showAnother}>
<button on:click={handleClickAnother}>Again please</button>
</Modal>
<Modal bind:display={showLast}>
<button on:click={handleClickLast}>Go back</button>
</Modal>
<script>
export let closeModal;
import { createEventDispatcher, onDestroy } from "svelte";
const dispatch = createEventDispatcher();
const dispatchClose = () => dispatch("close");
$: if (closeModal) {
dispatchClose();
}
let modal;
const handleKeydown = e => {
if (e.key === "Escape") {
console.log("handle keydown");
dispatchClose();
return;
}
if (e.key === "Tab") {
const nodes = modal.querySelectorAll("*");
const tabbable = Array.from(nodes).filter(n => n.tabIndex >= 0);
let index = tabbable.indexOf(document.activeElement);
if (index === -1 && e.shiftKey) index = 0;
index += tabbable.length + (e.shiftKey ? -1 : 1);
index %= tabbable.length;
tabbable[index].focus();
e.preventDefault();
}
};
const previouslyFocused =
typeof document !== "undefined" && document.activeElement;
if (previouslyFocused) {
onDestroy(() => {
previouslyFocused.focus();
});
}
</script>
<style>
.modal-background {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.3);
}
.modal {
position: fixed;
left: 50%;
top: 50%;
width: calc(100vw - 4em);
max-width: 32em;
max-height: calc(100vh - 4em);
overflow: auto;
transform: translate(-50%, -50%);
padding: 1em;
border-radius: 0.2em;
background: white;
}
</style>
<svelte:window on:keydown={handleKeydown} />
<div class="modal-background" on:click={dispatchClose} />
<div class="modal" role="dialog" aria-modal="true" bind:this={modal}>
<slot />
</div>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment