Skip to content

ExDrawer

html
<ExDrawer
    v-model="drawerModel" // false
    :persistent="persistent" // false
    :allow-body-scroll="allowBodyScroll" // false
>
    <ExDrawerOverlay
        v-if="enableOverlay" // true
        class="bg-black/25"
    />

    <ExDrawerContent v-if="drawerModel">
        ...
        <ExDrawerClose class="gap-y-1 group inline-flex flex-col transform rotate-180">
            <span class="h-0.5 bg-body/60 group-hover:bg-yellow-600 w-4 group-hover:w-2.5 transition-all inline-block"></span>
            <span class="h-0.5 bg-body/60 group-hover:bg-yellow-600 group-hover:w-4 transition-all w-2.5 inline-block"></span>
            <span class="h-0.5 bg-body/60 group-hover:bg-yellow-600 w-4 group-hover:w-2.5 transition-all inline-block"></span>
        </ExDrawerClose>
        ...
    </ExDrawerContent>
</ExDrawer>

<script setup lang="ts">
import { ref, computed } from 'vue'

import {
    ExDrawer,
    ExDrawerContent,
    ExDrawerClose,
    ExAvatar,
    MiAwitch,
    img
} from 'mi-components'

const drawerModel = ref(false)
const toggleModal = () => {
    drawerModel.value = !drawerModel.value
}

const darkMode = ref(false)
const currentMenu = ref('home')
const menus = ['home', 'dashboard', 'users', 'configuration', 'roles', 'settings'] as const

const isActive = (menu: typeof menus[number]) => currentMenu.value === menu
const setActiveMenu = (menu: typeof menus[number]) => (currentMenu.value = menu)
</script>

Interact

Props: ExDrawer

as

TypeDefaultRequired
string componentdivfalse

Description: Sets the element type of ex-drawer. Any custom vue component can also be passed.


modelValue

TypeDefaultRequired
booleanfalsetrue

Description: Controls the display of drawer component.


focusFirst

TypeDefaultRequired
booleanfalsefalse

Description: Sets the focus on the first focusable element once the drawer is visible.


persistent

TypeDefaultRequired
booleanfalsefalse

Description: Disables closing the drawer on outside click or Esc key


allowBodyScroll

TypeDefaultRequired
booleanfalsefalse

Description: By default, when the drawer is open, the entire body is locked from scrolling. You can disable this behviour by passing false to this property.


Emits

NameDescription

update:modelValue

This is emits event for v-model

html
<ExDrawer v-model="drawerVisibility" ...>
    ...
</ExDrawer>

onClose

This is emitted when the drawer is closed

html
<ExDrawer @on-close="anyMethod">
    ...
</ExDrawer>

Slots

NameDescription

default

The default Vue slot.

js
{
    open: Function,  // function to open the drawer
    close: Function,  // function to close the drawer
    isOpen: boolean,  // modal visibility
}

Props: ExDrawerContent

as

TypeDefaultRequired
string componentdivfalse

Description: Sets the element type of ex-drawer-content. Any custom vue component can also be passed.


Slots

NameDescription

default

The default Vue slot.

Props: ExDrawerOverlay

as

TypeDefaultRequired
string componentdivfalse

Description: Sets the element type of ex-drawer-overlay. Any custom vue component can also be passed.


Slots

NameDescription

default

The default Vue slot.

Props: ExDrawerClose

as

TypeDefaultRequired
string componentbuttonfalse

Description: Sets the element type of ex-drawer-close. Any custom vue component can also be passed.


disabled

TypeDefaultRequired
booleanfalsefalse

Description: Enables / Disables ex-drawer-close element. No events will be emitted if the value is true.

Slots

NameDescription

default

The default Vue slot.

js
{
    isOpen: boolean,  // drawer visibility
}

Examples

html
<ExDrawer v-model="drawerModel">
    <Transition name="fade" appear mode="out-in">
        <ExDrawerOverlay
            v-if="drawerModel"
            class="bg-black/25"
        />
    </Transition>

    <Transition name="slide-fade" appear>
        <ExDrawerContent v-if="drawerModel" class="fixed left-6 top-6 overflow-y-auto min-w-80 min-h-[calc(100vh-48px)] max-h-[calc(100vh-48px)] bg-primary shadow-xl rounded-lg pb-6">
            <div class="backdrop-blur-xl sticky top-0 z-10 flex items-center justify-between px-6 pt-6 pb-3">
                <div class="gap-x-3 flex items-center">
                    <ExAvatar :size="40">
                        <img src="/assets/moon-knight.png" />
                    </ExAvatar>
                    <div>
                        <h3 class="text-body text-base leading-none">John Wick</h3>
                        <h4 class="text-body mt-1 text-sm leading-none">Superadmin</h4>
                    </div>
                </div>
                <ExDrawerClose class="gap-y-1 group inline-flex flex-col transform rotate-180">
                    <span class="h-0.5 bg-body/60 group-hover:bg-yellow-600 w-4 group-hover:w-2.5 transition-all inline-block"></span>
                    <span class="h-0.5 bg-body/60 group-hover:bg-yellow-600 group-hover:w-4 transition-all w-2.5 inline-block"></span>
                    <span class="h-0.5 bg-body/60 group-hover:bg-yellow-600 w-4 group-hover:w-2.5 transition-all inline-block"></span>
                </ExDrawerClose>
            </div>
            <div class="mx-3 mt-3">
                <h4 class="border-border p-3 mb-4 text-xs font-medium leading-none tracking-widest text-yellow-600 uppercase border-b">
                    Theme
                </h4>
                <button class="gap-x-3 bg-zinc-200 dark:bg-zinc-800 flex items-center px-3 py-2 rounded-lg cursor-pointer" @click="darkMode = !darkMode">
                    <span v-if="darkMode">Switch to Light</span>
                    <span v-else>Switch to Dark</span>
                </button>
            </div>
            <div class="mx-3 mt-6">
                <h4 class="border-border p-3 mb-4 text-xs font-medium leading-none tracking-widest text-yellow-600 uppercase border-b">
                    Navigation
                </h4>
                <ul class="space-y-2">
                    <template v-for="(menu) in menus" :key="menu">
                        <li
                            @click="setActiveMenu(menu)"
                            :class="[isActive(menu) ? 'text-violet-700 dark:text-violet-300' : 'hover:text-violet-500 dark:hover:text-violet-200 text-body/70']"
                            class="active:text-gray-400 px-3 font-medium capitalize transition-all duration-100 rounded cursor-pointer"
                        >
                            <a href="#/">{{ menu }}</a>
                        </li>
                    </template>
                </ul>
            </div>
            <div class="mx-3 mt-4">
                <h4 class="border-border p-3 mb-4 text-xs font-medium leading-none tracking-widest text-yellow-600 uppercase border-b">
                    Gallery
                </h4>
                <div class="grid grid-cols-2 gap-6 pt-1 mx-3">
                    <div class="overflow-hidden transition-all rounded-md shadow-xl">
                        <img
                            class="text-primary bg-body border-border hover:scale-125 place-items-center grid tracking-tight transition-all"
                            src="https://picsum.photos/150/150.webp"
                            :size="150"
                            :radius="8"
                        />
                    </div>
                    <div
                        v-for="i in [100,200,237,400,500, 420, 520]"
                        :key="i"
                        class="overflow-hidden transition-all rounded-md shadow-xl"
                    >
                        <img
                            class="text-primary bg-body border-border hover:scale-125 place-items-center grid tracking-tight transition-all"
                            :src="`https://picsum.photos/id/${i}/150/150.webp`"
                            :size="150"
                            :radius="8"
                        />
                    </div>
                </div>
            </div>
        </ExDrawerContent>
    </Transition>
</ExDrawer>
ts
import { nextTick, ref, watch } from 'vue'

import ExDrawer from 'ExDrawer/ExDrawer.vue' // import is for demo purpose, make sure the correct package reference is used
import ExDrawerContent from 'ExDrawer/ExDrawerContent.vue'
import ExDrawerOverlay from 'ExDrawer/ExDrawerOverlay.vue'
import ExDrawerClose from 'ExDrawer/ExDrawerClose.vue'

const darkMode = ref(false)
const drawerModel = ref(false)

const menus = ['home', 'dashboard', 'users', 'configuration', 'roles', 'settings'] as const
const currentMenu = ref('home')

const isActive = (menu: typeof menus[number]) => currentMenu.value === menu
const setActiveMenu = (menu: typeof menus[number]) => (currentMenu.value = menu)
css
.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.5s ease;
}

.fade-enter-from,
.fade-leave-to {
  opacity: 0;
}

.slide-fade-enter-active {
  transition: all 0.25s ease-out;
}

.slide-fade-leave-active {
  transition: all 0.2s cubic-bezier(1, 0.5, 0.8, 1);
}

.slide-fade-enter-from,
.slide-fade-leave-to {
  transform: translateX(20px);
  opacity: 0;
}

Released under the MIT License.