Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
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: 3 days ago
JSON representation
A simple, small, and content-agnostic modal for Svelte v3 and v4
- Host: GitHub
- URL: https://github.com/flekschas/svelte-simple-modal
- Owner: flekschas
- License: mit
- Created: 2019-05-13T14:23:28.000Z (over 5 years ago)
- Default Branch: master
- Last Pushed: 2024-11-02T15:33:31.000Z (about 2 months ago)
- Last Synced: 2024-12-14T18:00:32.947Z (11 days ago)
- Topics: dialog, modal, popup, svelte, svelte-components, svelte-v3
- Language: Svelte
- Homepage: https://svelte.dev/repl/b95ce66b0ef34064a34afc5c0249f313
- Size: 1.17 MB
- Stars: 423
- Watchers: 6
- Forks: 33
- Open Issues: 10
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
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` keyTo 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)