Modal
This page is currently under construction
Lism UI (@lism-css/ui) is still in preparation.
A component for displaying modals using the dialog element.
Overview
↓
Preview
<Modal.OpenBtn modalId="modal-01" className="-bd -px:15 -py:5 -bdrs:10">Open Modal 01</Modal.OpenBtn>
<Modal.Root id="modal-01" aria-labelledby="modal-01-title" p="30"> <Modal.Inner layout="stack" pos="relative" max-sz="m" mx="auto" p="35" bdrs="30" bxsh="30"> <Modal.CloseBtn modalId="modal-01" autofocus pos="absolute" t="0" r="0" z="1" fz="xl" p="10" m="10" /> <Modal.Body layout="stack" g="30" util="trimAll"> <h2 className="-fz:l -fw:bold" id="modal-01-title">Modal Title</h2> <p>Lorem ipsum dolor sit amet. Consectetur adipiscing elit, sed do eiusmod tempor Incididunt ut. Labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut.</p> </Modal.Body> </Modal.Inner></Modal.Root><button class="-bd -px:15 -py:5 -bdrs:10 b--modal_openBtn set--plain -hov:-o" type="button" aria-haspopup="dialog" data-modal-open="modal-01">Open Modal 01</button>
<dialog class="b--modal set--plain -p:30" id="modal-01" aria-labelledby="modal-01-title"> <div class="b--modal_inner l--stack -pos:relative -max-sz:m -mx:auto -p:35 -bdrs:30 -bxsh:30"> <button class="b--modal_closeBtn set--plain -hov:-o -pos:absolute -t:0 -r:0 -z:1 -fz:xl -p:10 -m:10" type="button" data-modal-close="modal-01" autofocus> <svg class="a--icon" aria-hidden="true">...</svg> <span class="u--srOnly">Close</span> </button> <div class="b--modal_body l--stack u--trimAll -g:30"> <h2 class="-fz:l -fw:bold" id="modal-01-title">Modal Title</h2> <p>Lorem ipsum dolor sit amet. Consectetur adipiscing elit, sed do eiusmod tempor Incididunt ut. Labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut.</p> </div> </div></dialog>Add an id to <Modal.Root>, and pass the same modalId to <Modal.OpenBtn> / <Modal.CloseBtn> to wire up the open/close triggers.
- Do not change the
displayvalue of thedialogelement. - Due to animation issues with
::backdrop, this component assumes the dialog covers the full viewport width with a background color. - To announce the modal’s name to screen readers, specify
aria-labelledbyon<Modal.Root>pointing to the title element (e.g.h2). For modals without a visible title, usearia-labelinstead.
Styles
The Modal base styles are defined in the following CSS.
_style.css
/*
* dialog で実装.
* Memo: ::backdrop のアニメーションはFirefoxで動かない
*/
@layer lism-block {
.b--modal {
--flow: 0 !important; /* flow直下にきても影響しないように */
--duration: var(--modal-duration, 0.3s);
width: 100%;
height: 100%;
max-width: 100%;
max-height: 100%;
overflow: unset;
background: var(--backdrop-bg, rgb(0 0 0 / 0.5));
backdrop-filter: var(--modal-blur, blur(4px));
transition-duration: var(--duration);
transition-property: opacity;
}
.b--modal::backdrop {
background: none;
}
.b--modal[open] {
display: flex;
flex-direction: column;
justify-content: center;
}
.b--modal_inner {
--offset: 0 0; /* アニメーション用 */
background-color: var(--base);
transition: translate var(--duration);
max-height: 100%;
}
.b--modal_openBtn,
.b--modal_closeBtn {
display: inline-flex;
align-items: center;
}
.b--modal:not([data-is-open]) {
opacity: 0;
}
.b--modal:not([data-is-open]) > .b--modal_inner {
translate: var(--offset);
}
/* 減速設定時はアニメーションを無効化(duration プロップ由来の inline style よりも優先させるため !important) */
@media (prefers-reduced-motion: reduce) {
.b--modal {
--duration: 0s !important;
}
}
} The full source code is available on GitHub.
Usage
Provided as Modal from the @lism-css/ui package.
Import
import { Modal } from '@lism-css/ui/react'; import { Modal } from '@lism-css/ui/astro'; <link href="https://cdn.jsdelivr.net/npm/@lism-css/ui@0.30.0/dist/style.css" rel="stylesheet" /> <script type="module" src="https://cdn.jsdelivr.net/npm/@lism-css/ui@0.30.0/dist/scripts/modal.js"></script> <Modal.Root>, <Modal.Inner>, <Modal.Body>, <Modal.OpenBtn>, and <Modal.CloseBtn> are available.
Props
| Prop | Description |
|---|---|
id |
The id attribute is required on Modal (b--modal). |
<Modal.Root> duration |
Sets the duration of the modal open/close animation. Output as the --duration variable. |
<Modal.Inner> layout |
Specifies the layout component for __inner. |
<Modal.Inner> offset |
Offset value to shift the position of __inner when hidden. |
<Modal.OpenBtn> modalId |
Output as data-modal-open. Specifies the modal id on the trigger element that opens the modal. |
<Modal.CloseBtn> modalId |
Output as data-modal-close. Specifies the modal id on the trigger element that closes the modal. |
<Modal.CloseBtn> icon |
Specifies the icon displayed when no children are passed. (Default: x) |
<Modal.CloseBtn> srText |
Specifies the text output for screen readers when the icon is displayed. (Default: Close) |
Examples
To make <Modal.Body> scrollable, specify ov-y="auto". Place any content that should always remain visible before or after it.
Example with long content
↓
Modal example<Modal.OpenBtn modalId="modal-02" className="-bd -px:15 -py:5 -bdrs:10">Open Modal 02</Modal.OpenBtn>
<Modal.Root id="modal-02" aria-labelledby="modal-02-title" isContainer px="30" py="50"> <Modal.Inner layout="stack" max-sz="s" mx="auto" bdrs="20" bxsh="40"> <Flex ai="center" jc="between" py="15" bd-b> <Inline as="h2" id="modal-02-title" fz="l" fw="bold" hl="s" ms="30"> <Fragment>Modal Header</Fragment> </Inline> <Modal.CloseBtn modalId="modal-02" autofocus fz="xl" p="10" mx="15" /> </Flex> <Modal.Body layout="flow" px="30" py="20" ov-y="auto"> <DummyText /> <Box ar="16/9" bgc="base-2" bd /> <DummyText length="l" /> <DummyText length="s" /> <DummyText length="m" /> <Box ar="16/9" bgc="base-2" bd /> <DummyText length="xl" /> </Modal.Body> <Flex jc="end" px="30" py="15" bd-t> <Modal.CloseBtn modalId="modal-02" bgc="text" c="base" hl="s" px="15" py="10" bd="none" bdrs="10"> <Fragment>Cancel</Fragment> </Modal.CloseBtn> </Flex> </Modal.Inner></Modal.Root><button class="-bd -px:15 -py:5 -bdrs:10 b--modal_openBtn set--plain -hov:-o" type="button" aria-haspopup="dialog" data-modal-open="modal-02">Open Modal 02</button>
<dialog class="b--modal set--plain is--container -px:30 -py:50" id="modal-02" aria-labelledby="modal-02-title"> <div class="b--modal_inner l--stack -max-sz:s -mx:auto -bdrs:20 -bxsh:40"> <div class="l--flex -ai:center -jc:between -py:15 -bd-b"> <h2 class="-fz:l -fw:bold -hl:s -ms:30" id="modal-02-title">Modal Header</h2> <button class="b--modal_closeBtn set--plain -hov:-o -fz:xl -p:10 -mx:15" type="button" data-modal-close="modal-02" autofocus> <svg class="a--icon" aria-hidden="true">...</svg> <span class="u--srOnly">Close</span> </button> </div> <div class="b--modal_body l--flow -px:30 -py:20 -ov-y:auto"> <p>...Contents...</p> <div class="l--box -ar:16/9 -bgc:base-2 -bd"></div> <p>...Contents...</p> <p>...Contents...</p> <p>...Contents...</p> <div class="l--box -ar:16/9 -bgc:base-2 -bd"></div> <p>...Contents...</p> </div> <div class="l--flex -jc:end -px:30 -py:15 -bd-t"> <button class="b--modal_closeBtn set--plain -hov:-o -bgc:text -c:base -hl:s -px:15 -py:10 -bd:none -bdrs:10" type="button" data-modal-close="modal-02">Cancel</button> </div> </div></dialog>Drawer menu example
Clicking a same-page link (such as #id) inside the modal jumps to the target and closes the modal.
↓
Drawer menu example
import { MenuIcon } from '@lism-css/icons/react';
<Modal.OpenBtn modalId="modal-03" g="5" fz="s"> <Icon icon={MenuIcon} fz="l" /><span>MENU</span></Modal.OpenBtn>
<Modal.Root id="modal-03" aria-label="Menu"> <Modal.Inner layout="stack" max-w="24rem" h="100%" bxsh="40" offset="-100px 0"> <Flex bd-b ai="center" jc="between" p="20"> <Inline fw="bold">MENU</Inline> <Modal.CloseBtn modalId="modal-03" autofocus fz="xl" p="5" /> </Flex> <Modal.Body ov-y="auto"> <nav aria-label="Main menu"> <NavMenu.Root bd-b itemP="1em"> <NavMenu.Item> <NavMenu.Link href="#menu-link01">Menu item 1</NavMenu.Link> </NavMenu.Item> <NavMenu.Item> <NavMenu.Link href="#menu-link02">Menu item 2</NavMenu.Link> </NavMenu.Item> <NavMenu.Item> <NavMenu.Link href="#menu-link03">Menu item 3</NavMenu.Link> </NavMenu.Item> <NavMenu.Item> <NavMenu.Link href="#menu-link04">Menu item 4</NavMenu.Link> </NavMenu.Item> </NavMenu.Root> </nav> </Modal.Body> </Modal.Inner></Modal.Root><button class="b--modal_openBtn set--plain -hov:-o -g:5 -fz:s" type="button" aria-haspopup="dialog" data-modal-open="modal-03"> <svg class="a--icon -fz:l" aria-hidden="true">...</svg> <span>MENU</span></button>
<dialog class="b--modal set--plain" id="modal-03" aria-label="Menu"> <div class="b--modal_inner l--stack -max-w -h:100% -bxsh:40" style="--offset:-100px 0;--max-w:24rem"> <div class="l--flex -bd-b -ai:center -jc:between -p:20"> <span class="-fw:bold">MENU</span> <button class="b--modal_closeBtn set--plain -hov:-o -fz:xl -p:5" type="button" data-modal-close="modal-03" autofocus> <svg class="a--icon" aria-hidden="true">...</svg> <span class="u--srOnly">Close</span> </button> </div> <div class="b--modal_body -ov-y:auto"> <nav aria-label="Main menu"> <ul class="b--navMenu -bd-b" style="--item-p:1em"> <li class="b--navMenu_item"> <a class="b--navMenu_link -hov:-bgc" href="#menu-link01">Menu item 1</a> </li> <li class="b--navMenu_item"> <a class="b--navMenu_link -hov:-bgc" href="#menu-link02">Menu item 2</a> </li> <li class="b--navMenu_item"> <a class="b--navMenu_link -hov:-bgc" href="#menu-link03">Menu item 3</a> </li> <li class="b--navMenu_item"> <a class="b--navMenu_link -hov:-bgc" href="#menu-link04">Menu item 4</a> </li> </ul> </nav> </div> </div></dialog>