├── .editorconfig
├── .eslintrc.json
├── .github
├── dependabot.yml
├── pull_request_template.md
└── workflows
│ ├── build.yml
│ ├── publish.yml
│ └── release.yml
├── .gitignore
├── .huskyrc
├── .lintstagedrc
├── .nvm
├── .prettierrc
├── CHANGELOG.md
├── LICENSE
├── README.md
├── package-lock.json
├── package.json
├── rollup.config.js
├── src
├── Modal.svelte
└── index.js
└── types
├── Modal.svelte.d.ts
└── index.d.ts
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig helps developers define and maintain consistent
2 | # coding styles between different editors and IDEs
3 | # editorconfig.org
4 |
5 | root = true
6 |
7 | [*]
8 |
9 | # Change these settings to your own preference
10 | indent_style = space
11 | indent_size = 2
12 |
13 | # We recommend you to keep these unchanged
14 | end_of_line = lf
15 | charset = utf-8
16 | trim_trailing_whitespace = true
17 | insert_final_newline = true
18 |
19 | [*.md]
20 | trim_trailing_whitespace = false
21 |
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "parserOptions": {
3 | "ecmaVersion": 2021,
4 | "sourceType": "module"
5 | },
6 | "env": {
7 | "es6": true,
8 | "browser": true
9 | },
10 | "overrides": [
11 | {
12 | "files": ["*.svelte"],
13 | "parser": "svelte-eslint-parser"
14 | }
15 | ],
16 | "extends": ["eslint:recommended", "plugin:svelte/recommended"],
17 | "settings": {},
18 | "rules": {
19 | "arrow-spacing": 2,
20 | "keyword-spacing": [2, { "before": true, "after": true }],
21 | "no-console": ["error", { "allow": ["warn", "error"] }],
22 | "no-mixed-spaces-and-tabs": [2, "smart-tabs"],
23 | "no-var": 2,
24 | "object-shorthand": [2, "always"],
25 | "one-var": [2, "never"],
26 | "prefer-arrow-callback": 2,
27 | "prefer-const": 2,
28 | "quote-props": [2, "as-needed"],
29 | "semi": [2, "always"],
30 | "space-before-blocks": [2, "always"],
31 | "space-before-function-paren": [
32 | 2,
33 | { "anonymous": "always", "named": "never", "asyncArrow": "always" }
34 | ]
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: 'github-actions'
4 | directory: '/'
5 | schedule:
6 | interval: 'monthly'
7 |
--------------------------------------------------------------------------------
/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | Hi there 👋
2 |
3 | Thank you so much for creating a PR. To streamline the process and make sure that your changes can get merged easily, please stick to the following structure. See [#47](https://github.com/flekschas/svelte-simple-modal/pull/47) for an example of how to create an excellent PR description.
4 |
5 | ## Background
6 |
7 | Describe the context on how you use svelte-simple-modal. E.g., plain Svelte app, SvelteKit, Sapper, SSR, etc.
8 |
9 | ## Currently Observed Behavior
10 |
11 | Describe the current behavior and explain why you want to change it. If this is a bugfix PR, please reference the issue or describe it here in details.
12 |
13 | **Demo:** If this is a bugfix PR, please provide a live demo that reproduces the issue. E.g., you can fork the [current demo](https://svelte.dev/repl/033e824fad0a4e34907666e7196caec4).
14 |
15 | ## New Behavior
16 |
17 | Describe the changes that you introduce with this PR.
18 |
19 | **Demo:** Provide a live demo that implements the new behavior. E.g., you can fork the [current demo](https://svelte.dev/repl/033e824fad0a4e34907666e7196caec4).
20 |
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | # This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
3 |
4 | name: build
5 |
6 | on:
7 | push:
8 | branches: [master]
9 | pull_request:
10 | branches: [master]
11 |
12 | jobs:
13 | build:
14 | runs-on: ubuntu-latest
15 |
16 | strategy:
17 | matrix:
18 | node-version: [18.x, 20.x]
19 |
20 | steps:
21 | - uses: actions/checkout@v4
22 | - name: Use Node.js ${{ matrix.node-version }}
23 | uses: actions/setup-node@v4
24 | with:
25 | node-version: ${{ matrix.node-version }}
26 | - run: npm ci
27 | - run: npm run build --if-present
28 |
--------------------------------------------------------------------------------
/.github/workflows/publish.yml:
--------------------------------------------------------------------------------
1 | name: publish
2 |
3 | on:
4 | push:
5 | tags:
6 | - 'v*'
7 |
8 | jobs:
9 | build:
10 | runs-on: ubuntu-latest
11 | steps:
12 | - uses: actions/checkout@v4
13 | - uses: actions/setup-node@v4
14 | with:
15 | node-version: 20
16 | - run: sudo apt-get install xvfb
17 | - run: npm ci
18 | - run: npm run build --if-present
19 | env:
20 | CI: true
21 |
22 | publish-npm:
23 | needs: build
24 | runs-on: ubuntu-latest
25 | steps:
26 | - uses: actions/checkout@v4
27 | - uses: actions/setup-node@v4
28 | with:
29 | node-version: 20
30 | registry-url: https://registry.npmjs.org/
31 | - run: npm ci
32 | - run: npm run prerelease
33 | - run: npm publish
34 | env:
35 | NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
36 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: release
2 |
3 | on:
4 | push:
5 | tags:
6 | - 'v*'
7 |
8 | jobs:
9 | build:
10 | name: Create Release
11 | runs-on: ubuntu-latest
12 | steps:
13 | - name: Checkout code
14 | uses: actions/checkout@v4
15 | - name: Create Release
16 | id: create_release
17 | uses: actions/create-release@v1
18 | env:
19 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token
20 | with:
21 | tag_name: ${{ github.ref }}
22 | release_name: ${{ github.ref }}
23 | draft: false
24 | prerelease: false
25 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | index.js
4 | !src/index.js
5 | module.js
6 | dist.zip
7 |
--------------------------------------------------------------------------------
/.huskyrc:
--------------------------------------------------------------------------------
1 | {
2 | "hooks": {
3 | "pre-commit": "npm run precommit"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/.lintstagedrc:
--------------------------------------------------------------------------------
1 | {
2 | "*.svelte": [
3 | "pretty-quick --staged",
4 | "eslint --fix",
5 | "git add"
6 | ],
7 | }
8 |
--------------------------------------------------------------------------------
/.nvm:
--------------------------------------------------------------------------------
1 | 18
2 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true
3 | }
4 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # 2.0.0
2 |
3 | **BREAKING CHANGE:** Upgraded to Svelte v5. This change is unfortunately not backwards compatible with Svelte 3 or 4. If you want to use Svelte Simple Modal with Svelte v3 or v4, check out version 1 (https://github.com/flekschas/svelte-simple-modal/tree/v1) ([#119]https://github.com/flekschas/svelte-simple-modal/pull/119)
4 |
5 | # 1.6.2
6 |
7 | - Fix Svelte type resolve issue ([#107](https://github.com/flekschas/svelte-simple-modal/issues/107))
8 |
9 | # 1.6.1
10 |
11 | - Fix Svelte resolve warning ([#103](https://github.com/flekschas/svelte-simple-modal/issues/103))
12 |
13 | # 1.6.0
14 |
15 | - Enable usage with Svelte v4 (the library remains compatible with v3)
16 | - Update third-party libs
17 |
18 | # 1.5.2
19 |
20 | - Fix and expose context types. This is useful as an interim solution for ([#88](https://github.com/flekschas/svelte-simple-modal/pull/88)). E.g.:
21 |
22 | ```ts
23 | import { getContext } from 'svelte';
24 | import type { Context } from 'svelte-simple-modal';
25 | const { open, close } = getContext('simple-modal') as Context;
26 | ```
27 |
28 | # 1.5.1
29 |
30 | - Fix the scroll reset behavior to `instant` to avoid seeing a smooth scrolling when closing the modal in cases where the default scroll behavior was changed ([#97(https://github.com/flekschas/svelte-simple-modal/pull/97))
31 |
32 | # 1.5.0
33 |
34 | - Add property to assign an ID to the modal's root element ([#96(https://github.com/flekschas/svelte-simple-modal/pull/96))
35 |
36 | # 1.4.6
37 |
38 | - Improve type definition ([#94(https://github.com/flekschas/svelte-simple-modal/pull/94))
39 |
40 | # 1.4.5
41 |
42 | - Fix min-height issue with Safari iOS 15 ([#64](https://github.com/flekschas/svelte-simple-modal/issues/64))
43 |
44 | # 1.4.4
45 |
46 | - One more type definition improvement
47 |
48 | # 1.4.3
49 |
50 | - Further improve type definitions
51 |
52 | # 1.4.2
53 |
54 | - Improve type definitions
55 |
56 | # 1.4.1
57 |
58 | - Avoid submitting a `
` if it wraps `` by setting the close button type to `button`. ([#84](https://github.com/flekschas/svelte-simple-modal/pull/84)) Shoutout to [@jnysteen](https://github.com/jnysteen)!
59 |
60 | # 1.4.0
61 |
62 | - Skip untabbable element ([#82](https://github.com/flekschas/svelte-simple-modal/issues/82)) Massive thanks to [@jassenjj](https://github.com/jassenjj) 🙏
63 | - Added `isTabbable` property to allow users to override the tab-check. E.g., one might want to use a more the [tabbable library](https://github.com/focus-trap/tabbable#istabbable).
64 |
65 | # 1.3.4
66 |
67 | - Respect the tab order defined by `tabindex` attributes of elements within a modal ([#80](https://github.com/flekschas/svelte-simple-modal/pull/80))
68 |
69 | # 1.3.3
70 |
71 | - Fix accidentally removed global export of `bind()`
72 |
73 | # 1.3.2
74 |
75 | - Fix type issue of `bind()` via a new version of `sveld` (#73). See https://github.com/carbon-design-system/sveld/issues/83 for context. Also huge shoutout to [Dustin Coffey](https://github.com/dustinc) for [his PR (#75) on this matter](https://github.com/flekschas/svelte-simple-modal/pull/75). 🙏
76 |
77 | # 1.3.1
78 |
79 | - Updated `sveld` to fix the type definitions (#58). See https://github.com/carbon-design-system/sveld/issues/56 for context
80 |
81 | # 1.3.0
82 |
83 | - Add `classBg`, `classWindow`, `classWindowWrap`, `classContent`, and `classCloseButton` properties to applying custom CSS classes to the modal elements (#62)
84 | - Add `unstyled` to prevent applying default styles and providing full control over the modal styling
85 |
86 | # 1.2.0
87 |
88 | - Add `ariaLabel` and `ariaLabelledBy` to props/options to support improved accessibility (#37)
89 | - Add `aria-label="Close modal"` to the default close button component (#37)
90 |
91 | # 1.1.3
92 |
93 | - Add `"type": "module"` in `package.json` (#57)
94 |
95 | # 1.1.2
96 |
97 | - Properly export `bind()` (#58)
98 |
99 | # 1.1.1
100 |
101 | - Add type annotations via JSDocs, Typescript, and Sveld (#52)
102 |
103 | # 1.1.0
104 |
105 | - Add `disableFocusTrap` property for disabling the focus trap behavior (#49)
106 |
107 | # 1.0.4
108 |
109 | - Make sure that the modal only closes when it's open to fix (#53)
110 |
111 | # 1.0.3
112 |
113 | - Remove accidentally added `console.log` (#50) and forbid `console.log` via linting
114 |
115 | # 1.0.2
116 |
117 | - Revert changes from v1.0.1 as it turns out that in certain cases `overflow: hidden` on body is not enough to prevent background scrolling in iOS. For details see https://markus.oberlehner.net/blog/simple-solution-to-prevent-body-scrolling-on-ios/
118 |
119 | # 1.0.1
120 |
121 | - Remove `position: fixed` from body on opening a modal as it appears that the fixed positioning is not needed to avoid scrolling (#38)
122 |
123 | # 1.0.0
124 |
125 | Woohoo 🎉 Thanks everyone who uses and supports this library. This release
126 | really just introduces a bug fix but given that most (hopefully all 🤞) of the
127 | features are stable, I decided to finally release v1.
128 |
129 | - Fixes a scrolling issue introduced with #45 while still keeping the library compatible with SvelteKit (#47)
130 |
131 | # 0.10.4
132 |
133 | - Default bg width/height to innerWidth/innerHeight (#40)
134 | - Make compatible with svelte kit (#45)
135 |
136 | # 0.10.3
137 |
138 | - Avoid exception when converting falsy value to CSS (#42)
139 |
140 | # 0.10.2
141 |
142 | - Improve outer click handling and avoid accidental closing of the modal (#39)
143 |
144 | # 0.10.1
145 |
146 | - Harmonize `on:open`/`on:opening` and `on:close`/`on:closing` event (#33 and #34). Note, `on:opening` and `on:closing` are still being dispatched for backward compatibility but they will be remove in future versions so please switch over to `on:open` and `on:close`.
147 |
148 | # 0.10.0
149 |
150 | - Disable body scrolling while modal is open (#31 -> #28)
151 | - Fixed a visual glitch where previously customized styles were not reset
152 |
153 | # 0.9.0
154 |
155 | - Added `` as an alternative to other the context API (#22)
156 |
157 | # 0.8.1
158 |
159 | - Replace too strict `isSvelteComponent` with `isFunction` (#27)
160 |
161 | # 0.8.0
162 |
163 | - Dispatch open, opened, close, and closed events (#25)
164 |
165 | # 0.7.0
166 |
167 | - Allow customizing the window wrapper via `styleWindowWrap` (#24)
168 |
169 | # 0.6.1
170 |
171 | - Fall back gracefully for older versions of Svelte (`<3.19`) when `SvelteComponent` for the custom close button is not available (#21)
172 |
173 | # 0.6.0
174 |
175 | - Allow customizing the close button (#20)
176 |
177 | # 0.5.0
178 |
179 | - Trap focus in modal (#17)
180 | - Add `aria` information
181 |
182 | # 0.4.2
183 |
184 | - Explicitly expose the `event` object (#13)
185 |
186 | # 0.4.1
187 |
188 | - Remove wrapping `div` element as it's not necessary (#12)
189 |
190 | # 0.4.0
191 |
192 | - Add support for transition event callbacks via [`open(..., ..., ..., { onOpen, onOpened, onClose, onClosed })`](README.md#open))
193 |
194 | # 0.3.1
195 |
196 | - Fix non-reactive component (#11)
197 |
198 | # 0.3.0
199 |
200 | - Allow to specify instance-specific options via [`open(Component, componentProps, options)`](README.md#open))
201 |
202 | # 0.2.2
203 |
204 | - Update `package-lock.json` file
205 |
206 | # 0.2.1
207 |
208 | - Set backgroupd position to `top: 0` and `left: 0` by default thanks to https://github.com/flekschas/svelte-simple-modal/pull/5
209 |
210 | # 0.2.0
211 |
212 | - Allow customizing the modal style on `open(Component, props, styling)`. This can be used for content-aware theming.
213 |
214 | # 0.1.1
215 |
216 | - Robustify overflow
217 |
218 | # 0.1.0
219 |
220 | - First release
221 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Fritz Lekschas
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | Svelte Simple Modal
3 |
4 |
5 |
6 |
7 | **A simple, small, and content-agnostic modal for [Svelte](https://svelte.dev).**
8 |
9 |
28 |
29 | **Live demo:** https://svelte.dev/playground/b95ce66b0ef34064a34afc5c0249f313?version=5.17.3
30 |
31 | **Works with:** Svelte `>=v5`!
32 |
33 | > [!NOTE]
34 | > If you want to use Svelte Simple Modal with Svelte v3 or v4, check out [version 1](https://github.com/flekschas/svelte-simple-modal/tree/v1).
35 |
36 | ## Table of Contents
37 |
38 | - [Install](#install)
39 | - [Rollup Setup](#rollup-setup)
40 | - [Usage](#usage)
41 | - [TypeScript Example](#usage-with-typescript)
42 | - [Svelte Store Example](#usage-with-a-svelte-store)
43 | - [Styling](#styling)
44 | - [SSR](#server-side-rendering)
45 | - [Accessibility](#accessibility)
46 | - [API](#api)
47 | - [Component](#component-api)
48 | - [Events](#component-events)
49 | - [Context API](#context-api)
50 | - [Store API](#store-api)
51 | - [FAQ](#faq)
52 |
53 | ## Install
54 |
55 | ```bash
56 | npm install --save svelte-simple-modal
57 | ```
58 |
59 | #### Rollup Setup
60 |
61 | 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:
62 |
63 | ```js
64 | import resolve from '@rollup/plugin-node-resolve';
65 |
66 | export default {
67 | plugins: [
68 | resolve({
69 | dedupe: ['svelte', 'svelte/transition', 'svelte/internal'], // important!
70 | }),
71 | ],
72 | };
73 | ```
74 |
75 | ## Usage
76 |
77 | Import the `Modal` component into your main app component (e.g., `App.svelte`).
78 |
79 | The modal is exposing [two context functions](#context-api):
80 |
81 | - [`open()`](#open) opens a component as a modal.
82 | - [`close()`](#close) simply closes the modal.
83 |
84 | ```svelte
85 |
86 |
90 |
91 |
92 |
93 |
94 |
95 |
101 |
102 |
103 |
104 |
105 |
106 |
109 |
110 |
🎉 {message} 🍾
111 | ```
112 |
113 | **Demo:** https://svelte.dev/repl/52e0ade6d42546d8892faf8528c70d30
114 |
115 | ### Usage with TypeScript
116 |
117 | You can use the `Context` type exported by the package to validate the `getContext` function:
118 |
119 | ```ts
120 | import type { Context } from 'svelte-simple-modal';
121 | const { open } = getContext('simple-modal');
122 | // ...
123 | ```
124 |
125 | ### Usage With a Svelte Store
126 |
127 | Alternatively, you can use a [Svelte store](#store-api) to show/hide a component as a modal.
128 |
129 | ```svelte
130 |
131 |
138 |
139 |
140 |
141 |
142 | ```
143 |
144 | **Demo:** https://svelte.dev/repl/aec0c7d9f5084e7daa64f6d0c8ef0209
145 |
146 | The `` component is the same as in the example above.
147 |
148 | To hide the modal programmatically, simply unset the store. E.g., `modal.set(null)`.
149 |
150 | ### Styling
151 |
152 | 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.
153 |
154 | 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:
155 |
156 | ```svelte
157 |
166 |
167 |
168 | ```
169 |
170 | **Demo:** https://svelte.dev/repl/f2a988ddbd5644f18d7cd4a4a8277993
171 |
172 | > 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.
173 |
174 | Alternatively, you can also apply CSS styles directly via the `styleBg`, `styleWindow`, `styleWindowWrap`, `styleContent`, and `styleCloseButton` properties. For instance:
175 |
176 | ```svelte
177 |
182 |
183 |
184 | ```
185 |
186 | **Demo:** https://svelte.dev/repl/50df1c694b3243c1bd524b27f86eec51
187 |
188 | ### Server-Side Rendering
189 |
190 | 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:
191 |
192 | ```svelte
193 |
197 |
198 | {#if browser}
199 |
200 |
201 |
202 | {/if}
203 | ```
204 |
205 | Alternatively, you can enable SSR by dynamically importing svelte-simple-modal in `onMount()` as follows:
206 |
207 | ```js
208 | import { onMount } from 'svelte';
209 |
210 | onMount(async () => {
211 | const svelteSimpleModal = await import('svelte-simple-modal');
212 | Modal = svelteSimpleModal.default;
213 | });
214 | ```
215 |
216 | ### Accessibility
217 |
218 | The library applies the following WAI-ARIA guidelines for modal dialogs
219 | automtically:
220 |
221 | - `aria-modal="true"` and `role="dialog"` are applied automatically
222 | - The tab focus is trapped in the modal
223 | - The modal is closed on pressing the `esc` key
224 |
225 | To further improve the accessibility you'll have to either provide a label via
226 | [`ariaLabel`](https://www.w3.org/TR/wai-aria-1.1/#aria-label) or reference a
227 | title element via [`ariaLabelledBy`](https://www.w3.org/TR/wai-aria-1.1/#aria-labelledby).
228 | The `ariaLabel` is automatically omitted when `ariaLabelledBy` is specified.
229 |
230 | ## API
231 |
232 | ### Component API
233 |
234 | The `` component accepts the following optional properties:
235 |
236 | | Property | Type | Default | Description |
237 | | ------------------------- | ---------------------------------------------------- | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
238 | | **show** | Component \| null | `null` | A Svelte component to show as the modal. See [Store API](#store-api) for details. |
239 | | **id** | string \| null | `null` | Element ID to be assigned to the modal's root DOM element. |
240 | | **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. |
241 | | **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. |
242 | | **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. |
243 | | **closeOnEsc** | boolean | `true` | If `true` the modal will close when pressing the escape key. |
244 | | **closeOnOuterClick** | boolean | `true` | If `true` the modal will close when clicking outside the modal window. |
245 | | **transitionBg** | function | `svelte.fade` | Transition function for the background. |
246 | | **transitionBgProps** | BlurParams \| FadeParams \| FlyParams \| SlideParams | `{}` | Properties of the transition function for the background. |
247 | | **transitionWindow** | function | `svelte.fade` | Transition function for the window. |
248 | | **transitionWindowProps** | BlurParams \| FadeParams \| FlyParams \| SlideParams | `{}` | Properties of the transition function for the window. |
249 | | **classBg** | string \| null | `null` | Class name for the background element. |
250 | | **classWindowWrap** | string \| null | `null` | Class name for the modal window wrapper element. |
251 | | **classWindow** | string \| null | `null` | Class name for the modal window element. |
252 | | **classContent** | string \| null | `null` | Class name for the modal content element. |
253 | | **classCloseButton** | string \| null | `null` | Class name for the built-in close button. |
254 | | **styleBg** | Record | `{}` | Style properties of the background. |
255 | | **styleWindowWrap** | Record | `{}` | Style properties of the modal window wrapper element. |
256 | | **styleWindow** | Record | `{}` | Style properties of the modal window. |
257 | | **styleContent** | Record | `{}` | Style properties of the modal content. |
258 | | **styleCloseButton** | Record | `{}` | Style properties of the built-in close button. |
259 | | **unstyled** | boolean | `false` | When `true`, the default styles are not applied to the modal elements. |
260 | | **disableFocusTrap** | boolean | `false` | If `true` elements outside the modal can be in focus. This can be useful in certain edge cases. |
261 | | **isTabbable** | (node: Element): boolean | internal function | A function to determine if an HTML element is tabbable. |
262 | | **key** | string | `"simple-modal"` | The context key that is used to expose `open()` and `close()`. Adjust to avoid clashes with other contexts. |
263 | | **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. |
264 |
265 | ### Component Events
266 |
267 | The `` component dispatches the following events:
268 |
269 | - `open`: dispatched when the modal window starts to open.
270 | - `opened`: dispatched when the modal window opened.
271 | - `close`: dispatched when the modal window starts to close.
272 | - `closed`: dispatched when the modal window closed.
273 |
274 | Alternatively, you can listen to those events via callbacks passed to [`open()`](#open) and [`close()`](#close).
275 |
276 | ### Context API
277 |
278 | 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:
279 |
280 | ```js
281 | const { open, close } = getContext('simple-modal');
282 | ```
283 |
284 | #open(Component, props = {}, options = {}, callbacks = {})
285 |
286 | 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`:
287 |
288 | ```javascript
289 | {
290 | closeButton: false,
291 | closeOnEsc: false,
292 | closeOnOuterClick: false,
293 | transitionBg: fade,
294 | transitionBgProps: {
295 | duration: 5000
296 | },
297 | transitionWindow: fly,
298 | transitionWindowProps: {
299 | y: 100,
300 | duration: 250
301 | },
302 | styleBg: { backgroundImage: 'http://example.com/my-background.jpg' },
303 | styleWindow: { fontSize: '20em' },
304 | styleContent: { color: 'yellow' },
305 | styleCloseButton: { width: '3rem', height: '3rem' },
306 | disableFocusTrap: true
307 | }
308 | ```
309 |
310 | #close(callbacks = {})
311 |
312 | Closes the modal. Similar to `open()`, this method supports adding callbacks for the closing transition:
313 |
314 | ```javascript
315 | {
316 | onClose: () => { /* modal window starts to close */ },
317 | onClosed: () => { /* modal window closed */ },
318 | }
319 | ```
320 |
321 | Callbacks are triggered at the beginning and end of the opening and closing transition. The following callbacks are supported:
322 |
323 | ```javascript
324 | {
325 | onOpen: () => { /* modal window starts to open */ },
326 | onOpened: () => { /* modal window opened */ },
327 | onClose: () => { /* modal window starts to close */ },
328 | onClosed: () => { /* modal window closed */ },
329 | }
330 | ```
331 |
332 | ### Store API
333 |
334 | You can also use [Svelte stores](https://svelte.dev/tutorial/writable-stores) to open a modal using the ``'s [`show` property](#properties) as follows:
335 |
336 | ```svelte
337 |
338 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
🎉 Hi 🍾
352 | ```
353 |
354 | **Demo:** https://svelte.dev/repl/6f55b643195646408e780ceeb779ac2a
355 |
356 | 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 ``.
357 |
358 | #### Bind Props to a Component Shown as a Modal
359 |
360 | 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:
361 |
362 | ```svelte
363 |
370 | ```
371 |
372 | If you've worked with React/JSX then think of `const c = bind(Component, props)` as the equivalent of `const c = `.
373 |
374 | ## FAQ
375 |
376 | #### Custom Close Button
377 |
378 | **This feature requires Svelte >=v3.19!**
379 |
380 | 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()`.
381 |
382 | For example, your close button might look as follows:
383 |
384 | ```svelte
385 |
386 |
390 |
391 |
392 |
393 |
401 | ```
402 |
403 | Now you can set it as the default close button by passing it to `` as follows:
404 |
405 | ```svelte
406 |
407 |
412 |
413 |
414 |
415 |
416 | ```
417 |
418 | Or you can pass `CloseButton` to `open()` as shown below:
419 |
420 | ```svelte
421 |
422 |
433 |
434 |
435 | ```
436 |
437 | ## License
438 |
439 | [MIT](LICENSE)
440 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "svelte-simple-modal",
3 | "version": "2.0.0",
4 | "description": "A small and simple modal for Svelte",
5 | "type": "module",
6 | "svelte": "src/index.js",
7 | "main": "lib/index.js",
8 | "module": "lib/index.js",
9 | "types": "types/index.d.ts",
10 | "scripts": {
11 | "test": "echo \"Error: no test specified\" && exit 0",
12 | "build": "rm -rf lib && rm -rf types && rollup -c --bundleConfigAsCjs && sed -i '/from \"\"/d' types/index.d.ts && echo 'export { Context, Open, Close } from \"./Modal.svelte\";' >> types/index.d.ts && sed -i 's/SvelteComponentTyped/SvelteComponent/g' types/Modal.svelte.d.ts",
13 | "precommit": "NODE_ENV=production lint-staged; npm run lint",
14 | "prepare": "npm run lint && npm run build",
15 | "prerelease": "npm run lint; rm -f dist.zip; npm run build; zip dist.zip lib/* src/* types/*",
16 | "lint": "eslint src/* rollup.config.js"
17 | },
18 | "files": [
19 | "lib",
20 | "src",
21 | "types"
22 | ],
23 | "exports": {
24 | ".": {
25 | "svelte": "./src/index.js",
26 | "types": "./types/index.d.ts"
27 | }
28 | },
29 | "repository": {
30 | "type": "git",
31 | "url": "git+https://github.com/flekschas/svelte-simple-modal.git"
32 | },
33 | "keywords": [
34 | "svelte",
35 | "modal",
36 | "popup",
37 | "dialog"
38 | ],
39 | "author": "Fritz Lekschas",
40 | "license": "MIT",
41 | "bugs": {
42 | "url": "https://github.com/flekschas/svelte-simple-modal/issues"
43 | },
44 | "homepage": "https://github.com/flekschas/svelte-simple-modal#readme",
45 | "peerDependencies": {
46 | "svelte": "^5.0.0"
47 | },
48 | "devDependencies": {
49 | "@rollup/plugin-node-resolve": "^15.1.0",
50 | "@tsconfig/svelte": "^4.0.1",
51 | "eslint": "^8.43.0",
52 | "eslint-plugin-import": "^2.27.5",
53 | "eslint-plugin-svelte": "^2.31.1",
54 | "husky": "^4.3.8",
55 | "lint-staged": "^10.5.4",
56 | "prettier": "^2.8.8",
57 | "prettier-plugin-svelte": "^2.10.1",
58 | "pretty-quick": "^3.1.3",
59 | "rollup": "^3.25.2",
60 | "rollup-plugin-svelte": "^7.1.5",
61 | "sveld": "^0.20.0",
62 | "svelte": "^4.0.0",
63 | "svelte-eslint-parser": "^0.31.0",
64 | "typescript": "^5.1.3"
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/rollup.config.js:
--------------------------------------------------------------------------------
1 | /* eslint-env node */
2 | import node from '@rollup/plugin-node-resolve';
3 | import svelte from 'rollup-plugin-svelte';
4 | import { sveld } from 'sveld';
5 |
6 | import { readFileSync } from 'fs';
7 | const pkg = JSON.parse(readFileSync('./package.json'));
8 |
9 | const production = !process.env.ROLLUP_WATCH;
10 |
11 | export default {
12 | input: pkg.svelte,
13 | output: { format: 'es', file: pkg.module },
14 | plugins: [
15 | svelte({ emitCss: false }),
16 | node({
17 | browser: true,
18 | exportConditions: ['svelte'],
19 | extensions: ['.svelte'],
20 | }),
21 | production && sveld(),
22 | ],
23 | external: ['svelte', 'svelte/internal', 'svelte/transition'],
24 | };
25 |
--------------------------------------------------------------------------------
/src/Modal.svelte:
--------------------------------------------------------------------------------
1 |
38 |
39 |
469 |
470 |
471 |
472 | {#if Component}
473 |