Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/flekschas/svelte-simple-modal

A simple, small, and content-agnostic modal for Svelte v3 and v4
https://github.com/flekschas/svelte-simple-modal

dialog modal popup svelte svelte-components svelte-v3

Last synced: about 2 months ago
JSON representation

A simple, small, and content-agnostic modal for Svelte v3 and v4

Awesome Lists containing this project

README

        


svelte-simple-modal



**A simple, small, and content-agnostic modal for [Svelte](https://svelte.dev).**




[![NPM Version](https://img.shields.io/npm/v/svelte-simple-modal.svg?style=flat-square&color=7f99ff)](https://npmjs.org/package/svelte-simple-modal)
[![Build Status](https://img.shields.io/github/actions/workflow/status/flekschas/svelte-simple-modal/build.yml?branch=master&color=a17fff&style=flat-square)](https://github.com/flekschas/svelte-simple-modal/actions?query=workflow%3Abuild)
[![File Size](http://img.badgesize.io/https://unpkg.com/svelte-simple-modal/src/Modal.svelte?compression=gzip&style=flat-square&color=e17fff)](https://bundlephobia.com/result?p=svelte-simple-modal)
[![Code Style Prettier](https://img.shields.io/badge/code%20style-prettier-ff7fe1.svg?style=flat-square)](https://github.com/prettier/prettier#readme)
[![Demo](https://img.shields.io/badge/demo-👍-ff7fa5.svg?style=flat-square)](https://svelte.dev/repl/033e824fad0a4e34907666e7196caec4?version=3.18.2)



![simple-modal](https://user-images.githubusercontent.com/932103/57642565-9d335d00-7585-11e9-80c6-e4b835f02428.gif)

**Live demo:** https://svelte.dev/repl/033e824fad0a4e34907666e7196caec4?version=3.20.1

**Works with:** Svelte `>=v3.30` and `v4`!

## Table of Contents

- [Install](#install)
- [Rollup Setup](#rollup-setup)
- [Usage](#usage)
- [TypeScript Example](#usage-with-typescript)
- [Svelte Store Example](#usage-with-a-svelte-store)
- [Styling](#styling)
- [SSR](#server-side-rendering)
- [Accessibility](#accessibility)
- [API](#api)
- [Component](#component-api)
- [Events](#component-events)
- [Context API](#context-api)
- [Store API](#store-api)
- [FAQ](#faq)

## Install

```bash
npm install --save svelte-simple-modal
```

#### Rollup Setup

Make sure that the main application's version of `svelte` is used for bundling by setting `rollup-plugin-node-resolve`'s `dedupe` option as follows:

```js
import resolve from 'rollup-plugin-node-resolve';

export default {
plugins: [
resolve({
dedupe: ['svelte', 'svelte/transition', 'svelte/internal'], // important!
}),
],
};
```

## Usage

Import the `Modal` component into your main app component (e.g., `App.svelte`).

The modal is exposing [two context functions](#context-api):

- [`open()`](#open) opens a component as a modal.
- [`close()`](#close) simply closes the modal.

```svelte

import Content from './Content.svelte';
import Modal from 'svelte-simple-modal';

import { getContext } from 'svelte';
import Popup from './Popup.svelte';
const { open } = getContext('simple-modal');
const showSurprise = () => open(Popup, { message: "It's a modal!" });

Show me a surprise!

export let message = 'Hi';

🎉 {message} 🍾


```

**Demo:** https://svelte.dev/repl/52e0ade6d42546d8892faf8528c70d30

### Usage with TypeScript

You can use the `Context` type exported by the package to validate the `getContext` function:

```ts
import type { Context } from 'svelte-simple-modal';
const { open } = getContext('simple-modal');
// ...
```

### Usage With a Svelte Store

Alternatively, you can use a [Svelte store](#store-api) to show/hide a component as a modal.

```svelte

import { writable } from 'svelte/store';
import Modal, { bind } from 'svelte-simple-modal';
import Popup from './Popup.svelte';
const modal = writable(null);
const showModal = () => modal.set(bind(Popup, { message: "It's a modal!" }));

Show modal

```

**Demo:** https://svelte.dev/repl/aec0c7d9f5084e7daa64f6d0c8ef0209

The `` component is the same as in the example above.

To hide the modal programmatically, simply unset the store. E.g., `modal.set(null)`.

### Styling

The modal comes pre-styled for convenience but you can easily extent or replace the styling using either custom CSS classes or explicit CSS styles.

Custom CSS classes can be applied via the `classBg`, `classWindow`, `classWindowWrap`, `classContent`, and `classCloseButton` properties. For instance, you could customize the styling with [TailwindCSS](https://tailwindcss.com/) as follows:

```svelte

Show modal

```

**Demo:** https://svelte.dev/repl/f2a988ddbd5644f18d7cd4a4a8277993

> Note: to take full control over the modal styles with CSS classes you have to reset existing styles via `unstyled={true}` as internal CSS classes are always applied last due to Svelte's class scoping.

Alternatively, you can also apply CSS styles directly via the `styleBg`, `styleWindow`, `styleWindowWrap`, `styleContent`, and `styleCloseButton` properties. For instance:

```svelte

Show modal

```

**Demo:** https://svelte.dev/repl/50df1c694b3243c1bd524b27f86eec51

### Server-Side Rendering

With [SvelteKit](https://kit.svelte.dev/) you can enable [SSR](https://www.google.com/search?q=server+side+rendering) using the `browser` environmental variable as follows:

```svelte

import Modal from 'svelte-simple-modal';
import { browser } from '$app/env';

{#if browser}



{/if}
```

Alternatively, you can enable SSR by dynamically importing svelte-simple-modal in `onMount()` as follows:

```js
import { onMount } from 'svelte';

onMount(async () => {
const svelteSimpleModal = await import('svelte-simple-modal');
Modal = svelteSimpleModal.default;
});
```

### Accessibility

The library applies the following WAI-ARIA guidelines for modal dialogs
automtically:

- `aria-modal="true"` and `role="dialog"` are applied automatically
- The tab focus is trapped in the modal
- The modal is closed on pressing the `esc` key

To further improve the accessibility you'll have to either provide a label via
[`ariaLabel`](https://www.w3.org/TR/wai-aria-1.1/#aria-label) or reference a
title element via [`ariaLabelledBy`](https://www.w3.org/TR/wai-aria-1.1/#aria-labelledby).
The `ariaLabel` is automatically omitted when `ariaLabelledBy` is specified.

## API

### Component API

The `` component accepts the following optional properties:

| Property | Type | Default | Description |
| ------------------------- | ---------------------------------------------------- | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **show** | Component \| null | `null` | A Svelte component to show as the modal. See [Store API](#store-api) for details. |
| **id** | string \| null | `null` | Element ID to be assigned to the modal's root DOM element. |
| **ariaLabel** | string \| null | `null` | Accessibility label of the modal. See [W3C WAI-ARIA](https://www.w3.org/TR/wai-aria-1.1/#aria-label) for details. |
| **ariaLabelledBy** | string \| null | `null` | Element ID holding the accessibility label of the modal. See [W3C WAI-ARIA](https://www.w3.org/TR/wai-aria-1.1/#aria-labelledby) for details. |
| **closeButton** | Component \| boolean | `true` | If `true` a button for closing the modal is rendered. You can also pass in a [custom Svelte component](#custom-close-button) to have full control over the styling. |
| **closeOnEsc** | boolean | `true` | If `true` the modal will close when pressing the escape key. |
| **closeOnOuterClick** | boolean | `true` | If `true` the modal will close when clicking outside the modal window. |
| **transitionBg** | function | `svelte.fade` | Transition function for the background. |
| **transitionBgProps** | BlurParams \| FadeParams \| FlyParams \| SlideParams | `{}` | Properties of the transition function for the background. |
| **transitionWindow** | function | `svelte.fade` | Transition function for the window. |
| **transitionWindowProps** | BlurParams \| FadeParams \| FlyParams \| SlideParams | `{}` | Properties of the transition function for the window. |
| **classBg** | string \| null | `null` | Class name for the background element. |
| **classWindowWrap** | string \| null | `null` | Class name for the modal window wrapper element. |
| **classWindow** | string \| null | `null` | Class name for the modal window element. |
| **classContent** | string \| null | `null` | Class name for the modal content element. |
| **classCloseButton** | string \| null | `null` | Class name for the built-in close button. |
| **styleBg** | Record | `{}` | Style properties of the background. |
| **styleWindowWrap** | Record | `{}` | Style properties of the modal window wrapper element. |
| **styleWindow** | Record | `{}` | Style properties of the modal window. |
| **styleContent** | Record | `{}` | Style properties of the modal content. |
| **styleCloseButton** | Record | `{}` | Style properties of the built-in close button. |
| **unstyled** | boolean | `false` | When `true`, the default styles are not applied to the modal elements. |
| **disableFocusTrap** | boolean | `false` | If `true` elements outside the modal can be in focus. This can be useful in certain edge cases. |
| **isTabbable** | (node: Element): boolean | internal function | A function to determine if an HTML element is tabbable. |
| **key** | string | `"simple-modal"` | The context key that is used to expose `open()` and `close()`. Adjust to avoid clashes with other contexts. |
| **setContext** | function | `svelte.setContent` | You can normally ingore this property when you have [configured Rollup properly](#rollup-setup). If you want to bundle simple-modal with its own version of Svelte you have to pass `setContext()` from your main app to simple-modal using this parameter. |

### Component Events

The `` component dispatches the following events:

- `open`: dispatched when the modal window starts to open.
- `opened`: dispatched when the modal window opened.
- `close`: dispatched when the modal window starts to close.
- `closed`: dispatched when the modal window closed.

Alternatively, you can listen to those events via callbacks passed to [`open()`](#open) and [`close()`](#close).

### Context API

Svelte Simple Modal uses [Svelte's context API](https://svelte.dev/tutorial/context-api) to expose the `open()` and `close()` methods. You can get these methods as follows:

```js
const { open, close } = getContext('simple-modal');
```

# open(Component, props = {}, options = {}, callbacks = {})

Opens the modal with `` rendered as the content. `options` can be used to adjust the modal behavior once for the modal that is about to be opened. The `options` allows to customize all [parameters](#parameters) except `key` and `setContext`:

```javascript
{
closeButton: false,
closeOnEsc: false,
closeOnOuterClick: false,
transitionBg: fade,
transitionBgProps: {
duration: 5000
},
transitionWindow: fly,
transitionWindowProps: {
y: 100,
duration: 250
},
styleBg: { backgroundImage: 'http://example.com/my-background.jpg' },
styleWindow: { fontSize: '20em' },
styleContent: { color: 'yellow' },
styleCloseButton: { width: '3rem', height: '3rem' },
disableFocusTrap: true
}
```

# close(callbacks = {})

Closes the modal. Similar to `open()`, this method supports adding callbacks for the closing transition:

```javascript
{
onClose: () => { /* modal window starts to close */ },
onClosed: () => { /* modal window closed */ },
}
```

Callbacks are triggered at the beginning and end of the opening and closing transition. The following callbacks are supported:

```javascript
{
onOpen: () => { /* modal window starts to open */ },
onOpened: () => { /* modal window opened */ },
onClose: () => { /* modal window starts to close */ },
onClosed: () => { /* modal window closed */ },
}
```

### Store API

You can also use [Svelte stores](https://svelte.dev/tutorial/writable-stores) to open a modal using the ``'s [`show` property](#properties) as follows:

```svelte

import { writable } from 'svelte/store';
import Modal from 'svelte-simple-modal';
import Popup from './Popup.svelte';
const modal = writable(null);
const showModal = () => modal.set(Popup);

Show modal

🎉 Hi 🍾


```

**Demo:** https://svelte.dev/repl/6f55b643195646408e780ceeb779ac2a

An added benefit of using stores is that the component opening the modal does not have to be a parent of ``. For instance, in the example above, `App.svelte` is toggling `Popup.svelte` as a modal even though `App.svelte` is not a child of ``.

#### Bind Props to a Component Shown as a Modal

Sometimes you want to pass properties to the component shown as a modal. To accomplish this, you can use our `bind()` helper function as follows:

```svelte

import { bind } from 'svelte-simple-modal';
import Popup from './Popup.svelte';
import { modal } from './App.svelte';

modal.set(bind(Popup, { name: 'custom name' }));

```

If you've worked with React/JSX then think of `const c = bind(Component, props)` as the equivalent of `const c = `.

## FAQ

#### Custom Close Button

**This feature requires Svelte >=v3.19!**

Unfortunately, it's not possible to adjust all styles of the built-in close button via the `styleCloseButton` option. If you need full control you can implement your own Svelte component and use that as the close button. To do so pass your component via the `closeButton` option to `` or `open()`.

For example, your close button might look as follows:

```svelte

// This property is used by Modal.svelte to pass down the close function
export let onClose;

Custom Close Button

/* Customize to your liking */
button {
position: absolute;
top: -3rem;
right: 0;
}

```

Now you can set it as the default close button by passing it to `` as follows:

```svelte

import Content from './Content.svelte';
import CloseButton from './CloseButton.svelte';
import Modal from 'svelte-simple-modal';

```

Or you can pass `CloseButton` to `open()` as shown below:

```svelte

import { getContext } from 'svelte';
import Surprise from './Surprise.svelte';
import CloseButton from './CloseButton.svelte';

const { open } = getContext('simple-modal');

const showSurprise = () => {
open(Surprise, { message: "It's a modal!" }, { closeButton: CloseButton });
};

Show me a surprise!


```

## License

[MIT](LICENSE)