Skip to content

Drawer ​

Provides a scroll drawer that uses native CSS scroll-snap property.
Can be dismissed with touch gestures on touch devices.

View Source 

Usage ​

css
@import "winduum/src/components/drawer/index.css" layer(components);
html
<button class="ui-btn" id="showDrawerLeftElement">Show drawer</button>
<div class="c-drawer invisible" id="drawerLeftElement" inert>
    <nav class="c-drawer-content">
        Drawer content
        <button class="ui-btn muted" id="closeDrawerLeftElement">Close drawer</button>
    </nav>
</div>
liquid
<script type="module">
    import { showDrawer, closeDrawer, scrollDrawer } from "winduum/src/components/drawer"

    drawerLeftElement?.scroll({ left: drawerLeftElement?.scrollWidth , behavior: 'instant' })
    drawerLeftElement?.classList.remove('invisible')

    drawerLeftElement.addEventListener('scroll', ({ target }) => scrollDrawer(target))
    showDrawerLeftElement.addEventListener('click', () => showDrawer(drawerLeftElement))
    closeDrawerLeftElement.addEventListener('click', () => closeDrawer(drawerLeftElement))
</script>

Variants ​

  • default 
  • content 

Props ​

  • default-props 
  • content-props 

Installation ​

Follow instructions for individual framework usage below

  • winduum 

Examples ​

Left ​

html
<button class="ui-btn" id="showDrawerLeftElement">Show drawer</button>
<div class="c-drawer invisible" id="drawerLeftElement" inert>
    <nav class="c-drawer-content">
        Drawer content
        <button class="ui-btn muted" id="closeDrawerLeftElement">Close drawer</button>
    </nav>
</div>
liquid
<script type="module">
    import { showDrawer, closeDrawer, scrollDrawer } from "winduum/src/components/drawer"

    drawerLeftElement?.scroll({ left: drawerLeftElement?.scrollWidth , behavior: 'instant' })
    drawerLeftElement?.classList.remove('invisible')

    drawerLeftElement.addEventListener('scroll', ({ target }) => scrollDrawer(target))
    showDrawerLeftElement.addEventListener('click', () => showDrawer(drawerLeftElement))
    closeDrawerLeftElement.addEventListener('click', () => closeDrawer(drawerLeftElement))
</script>
html
<button class="ui-btn" id="showDrawerRightElement">Show drawer</button>
<div class="c-drawer invisible after:-order-last" id="drawerRightElement" inert>
    <nav class="c-drawer-content">
        Drawer content
        <button class="ui-btn muted" id="closeDrawerRightElement">Close drawer</button>
    </nav>
</div>
liquid
<script type="module">
    import { showDrawer, closeDrawer, scrollDrawer } from "winduum/src/components/drawer"

    drawerRightElement?.scroll({ left: 0, behavior: 'instant' });
    drawerRightElement?.classList.remove('invisible')

    drawerRightElement.addEventListener('scroll', ({ target }) => scrollDrawer(target, {
        scrollOpen: target.scrollWidth - target.clientWidth,
        scrollClose: 0,
        opacityRatio: 0
    }))
    showDrawerRightElement.addEventListener('click', () => showDrawer(drawerRightElement, drawerRightElement.scrollWidth))
    closeDrawerRightElement.addEventListener('click', () => closeDrawer(drawerRightElement, 0))
</script>

Bottom ​

html
<button class="ui-btn" id="showDrawerBottomElement">Show drawer</button>
<div class="c-drawer invisible flex-col after:-order-last" id="drawerBottomElement" inert>
    <nav class="c-drawer-content" style="--c-drawer-content-width: 100%;--c-drawer-content-height: calc(100vh - 4rem);">
        Drawer content
        <button class="ui-btn muted" id="closeDrawerBottomElement">Close drawer</button>
    </nav>
</div>
liquid
<script type="module">
    import { showDrawer, closeDrawer, scrollDrawer } from "winduum/src/components/drawer"

    drawerBottomElement?.scroll({ top: 0, behavior: 'instant' });
    drawerBottomElement?.classList.remove('invisible')

    drawerBottomElement.addEventListener('scroll', ({ target }) => scrollDrawer(target, {
        snapClass: 'snap-y snap-mandatory',
        scrollSize: target.scrollHeight - target.clientHeight,
        scrollDirection: target.scrollTop,
        scrollOpen: target.scrollHeight - target.clientHeight,
        scrollClose: 0,
        opacityRatio: 0
    }))
    showDrawerBottomElement.addEventListener('click', () => showDrawer(drawerBottomElement, drawerBottomElement.scrollHeight, 'top'))
    closeDrawerBottomElement.addEventListener('click', () => closeDrawer(drawerBottomElement, 0, 'top'))
</script>

Top ​

html
<button class="ui-btn" id="showDrawerTopElement">Show drawer</button>
<div class="c-drawer invisible flex-col" id="drawerTopElement" inert>
    <nav class="c-drawer-content" style="--c-drawer-content-width: 100%;--c-drawer-content-height: calc(100vh - 4rem);">
        Drawer content
        <button class="ui-btn muted" id="closeDrawerTopElement">Close drawer</button>
    </nav>
</div>
liquid
<script type="module">
    import { showDrawer, closeDrawer, scrollDrawer } from "winduum/src/components/drawer"

    drawerTopElement?.scroll({ top: drawerTopElement.scrollHeight, behavior: 'instant' });
    drawerTopElement?.classList.remove('invisible')

    drawerTopElement.addEventListener('scroll', ({ target }) => scrollDrawer(target, {
        snapClass: 'snap-y snap-mandatory',
        scrollSize: target.scrollHeight - target.clientHeight,
        scrollDirection: target.scrollTop,
        scrollOpen: 0,
        scrollClose: target.scrollHeight - target.clientHeight
    }))
    showDrawerTopElement.addEventListener('click', () => showDrawer(drawerTopElement, 0, 'top'))
    closeDrawerTopElement.addEventListener('click', () => closeDrawer(drawerTopElement, drawerTopElement.scrollHeight, 'top'))
</script>

Dialog ​

Moves the drawer to top layer, traps focus in and can be closed with esc.

html
<button class="ui-btn" id="showDrawerDialogElement">Show drawer</button>
<dialog class="c-drawer invisible after:-order-last backdrop:hidden" id="drawerDialogElement" inert>
    <nav class="c-drawer-content">
        Drawer content
        <button class="ui-btn muted" id="closeDrawerDialogElement">Close drawer</button>
    </nav>
</dialog>
liquid
<script type="module">
    import { showDrawer, closeDrawer, scrollDrawer } from "winduum/src/components/drawer"

    drawerDialogElement?.scroll({ left: 0, behavior: 'instant' });
    drawerDialogElement?.classList.remove('invisible')

    drawerDialogElement.addEventListener('scroll', ({ target }) => scrollDrawer(target, {
        scrollOpen: target.scrollWidth - target.clientWidth,
        scrollClose: 0,
        opacityRatio: 0
    }))
    showDrawerDialogElement.addEventListener('click', () => {
        drawerDialogElement.showModal()
        showDrawer(drawerDialogElement, drawerDialogElement.scrollWidth)
    })
    closeDrawerDialogElement.addEventListener('click', () => closeDrawer(drawerDialogElement, 0))

    drawerDialogElement?.addEventListener('c-drawer:close', () => drawerDialogElement.close())
    drawerDialogElement?.addEventListener('close', () => closeDrawer(drawerDialogElement, 0))
</script>

Javascript API ​

showDrawer ​

  • Type: (element: HTMLElement | Element, distance: number, direction: 'left' | 'top') => void
  • Kind: sync

Scrolls the drawer to opened state.

closeDrawer ​

  • Type: (element: HTMLElement | Element, distance: number, direction: 'left' | 'top') => void
  • Kind: sync

Scrolls the drawer to closed state.

scrollDrawer ​

  • Type: (element: HTMLElement | Element, options: ScrollDrawerOptions) => void
  • Kind: sync

Sets correct classes and attributes upon scroll. Events c-drawer:open and c-drawer:close are dispatched upon opening or closing the drawer.

ScrollDrawerOptions ​


snapClass ​
  • Type: string
  • Default: snap-x snap-mandatory

A classes that are added for snapping purposes once the drawer is open.


opacityProperty ​
  • Type: string
  • Default: --tw-bg-opacity

A CSS property for animating the background opacity upon scroll.


opacityRatio ​
  • Type: number
  • Default: 1

You can either set 1 or 0 depending on the direction the drawer is opened. Right and bottom drawer should be set to 0.


scrollOpen ​
  • Type: number
  • Default: 0

Scroll position indicating that the drawer is opened.


scrollClose ​
  • Type: number
  • Default: element.scrollWidth - element.clientWidth

Scroll position indicating that the drawer is closed.


scrollSize ​
  • Type: number
  • Default: element.scrollWidth - element.clientWidth

Maximum scroll size of the drawer.


scrollDirection ​
  • Type: number
  • Default: element.scrollLeft

Current scroll position of the drawer.

Released under the MIT License.