jb-modal
v1.13.1
Published
modal web component
Maintainers
Readme
jb-modal
Responsive modal web component.
Benefits:
- Responsive, opens as a centered dialog on desktop and a bottom sheet on mobile devices.
- Framework free, so you can use it anywhere.
- Customizable content and style.
- Pre-styled header and footer slots.
- TypeScript support.
- Optional auto close on background click.
- Optional route history with browser back handling.
- Keeps modal open after page refresh when you provide an
id.
When to use
Use jb-modal for temporary blocking UI such as confirmations, forms, detail views, and mobile bottom sheets.
Use an inline panel or page route when the content should remain part of the normal document flow or needs a shareable full-page URL.
Demo
Using With JS Frameworks
Installation
npm i jb-modalimport 'jb-modal';<jb-modal>
<div>Modal content</div>
</jb-modal>API reference
Attributes
| name | type | default | description |
| --- | --- | --- | --- |
| is-open | boolean | false | Opens the modal when set to "true". Any other value closes it. |
| id | string | "" | Modal id used for URL hash state. |
Properties
| name | type | readonly | description |
| --- | --- | --- | --- |
| isOpen | boolean | yes | Current isOpen state. |
| id | string | no | Modal id used for URL hash state. See the Hash Id Storybook docs. |
| config | { autoCloseOnBackgroundClick: boolean } | no | Runtime configuration. |
Methods
| name | returns | description |
| --- | --- | --- |
| open() | void | Opens the modal, sets ariaHidden to false, and pushes #id to browser history when id is set. |
| close() | void | Closes the modal, sets ariaHidden to true, and navigates back when the current URL hash matches the modal id. |
Events
| event | detail | description |
| --- | --- | --- |
| load | none | Dispatched from connectedCallback before initialization. |
| init | none | Dispatched from connectedCallback after initialization. |
| urlOpen | none | Dispatched when the modal opens itself because the current URL hash matches its id. |
| close | { eventType } | Dispatched for background click and browser-back close attempts. |
close event event.detail.eventType can be:
| value | meaning |
| --- | --- |
| BACKGROUND_CLICK | The backdrop was clicked. |
| HISTORY_BACK_EVENT | Browser back/popstate was received while the modal was open. |
| CLOSE_BUTTON_CLICK | Reserved close type for close button flows. |
isOpen and close
const modal = document.querySelector('jb-modal');
modal.open();
modal.close();
console.log(modal.isOpen);<jb-modal is-open="true">
<div>Modal content</div>
</jb-modal>Slots
Use the default slot for simple content or named slots for structured modal sections.
<jb-modal>
<div slot="header">Modal header</div>
<div slot="content">Modal content</div>
<div slot="footer">
<jb-button>Done</jb-button>
</div>
</jb-modal>| slot | description |
| --- | --- |
| default | Modal content rendered as the fallback of the content slot. |
| header | Header area at the top of the content box. |
| content | Main scrollable modal content area. |
| footer | Footer area at the bottom of the content box. |
Background click
The component always dispatches close with eventType: "BACKGROUND_CLICK" when the backdrop is clicked. It only closes automatically when config.autoCloseOnBackgroundClick is true.
const modal = document.querySelector('jb-modal');
modal.config.autoCloseOnBackgroundClick = true;
modal.addEventListener('close', (event) => {
if (event.detail.eventType === 'BACKGROUND_CLICK') {
console.log('Backdrop clicked');
}
});URL hash state
Set id when the modal should update the URL hash while isOpen is true. When open() runs, the modal pushes #id to browser history. If the page loads with the same hash, the modal opens itself and dispatches urlOpen.
Demo: Hash Id Storybook docs. To test the real browser hash and back-button behavior, open the isolated hash demo in a new window.
<jb-modal id="profile-modal">
<div slot="content">Profile</div>
</jb-modal>const modal = document.querySelector('#profile-modal');
modal.addEventListener('urlOpen', () => {
console.log('Opened from URL hash');
});Browser back dispatches a close event with eventType: "HISTORY_BACK_EVENT". In the current implementation, browser-back auto close uses the same config.autoCloseOnBackgroundClick flag.
CSS parts and custom style
| part | description |
| --- | --- |
| background | The modal backdrop/background. |
| content-box | The modal content box that contains header, content, and footer slots. |
| component-wrapper | div that wrap whole component |
| CSS variable name | description |
| --- | --- |
| --jb-modal-bg-color | Modal content background color. |
| --jb-modal-back-bg-color | Modal backdrop background color. |
| --jb-modal-border-radius | Modal content border radius. |
| --jb-modal-z-index | Modal z-index. |
jb-modal::part(content-box) {
min-width: 320px;
}
jb-modal {
--jb-modal-border-radius: 16px;
--jb-modal-z-index: 1000;
}Animation
jb-modal does not ship with a default desktop open or close animation. Modal animation is usually tied to each project's visual language, motion duration, easing, and interaction style, so the component keeps the behavior simple and lets you add animation from your own CSS.
You can animate each exposed part independently. For example, fade the background, scale or slide the content-box, or use different durations for each part.
@media (min-width: 769px) {
.profile-modal::part(background) {
opacity: 1;
transition: opacity 300ms ease;
}
.profile-modal::part(content-box) {
opacity: 1;
transform: translateY(0) scale(1);
transition:
opacity 300ms ease,
transform 300ms cubic-bezier(0.16, 1, 0.3, 1);
}
.profile-modal:state(open)::part(background) {
@starting-style {
opacity: 0;
}
}
.profile-modal:state(open)::part(content-box) {
@starting-style {
opacity: 0;
transform: translateY(1rem) scale(0.96);
}
}
}For close animations, include a discrete display transition on the modal host so the element remains rendered while its parts animate back to their closed styles.
See the Animation Storybook docs for open-only and open-close examples.
Accessibility notes
- The component attaches
ElementInternalsand setsariaModaltotrue. ariaHiddenis set tofalsewhen opened andtruewhen closed.
Related Docs
- See
jb-modal/reactif you want to use this component in React. - See All JB Design System Component List for more components.
- Use Contribution Guide if you want to contribute to this component.
AI agent notes
- Import
jb-modalonce before using<jb-modal>. - Use
open()andclose()for imperative control; there is no publicopenproperty setter. - Use
is-open="true"only for initialisOpenmarkup state. - Use
config.autoCloseOnBackgroundClick = truewhen backdrop clicks should close the modal. - Listen to
closeand inspectevent.detail.eventTypeto know why close was requested. - Use
idonly when URL hash/history integration is desired. - This package includes
custom-elements.jsonand points to it with the package.jsoncustomElementsfield. The field is documented by the Custom Elements Manifest project in Referencing manifests from npm packages. - In
custom-elements.json,exports.kind: "js"describes JavaScript/TypeScript exports andexports.kind: "custom-element-definition"maps thejb-modaltag name toJBModalWebComponent.
