Skip to content

Slide over

A slide over is a modal-like interface that slides in from the side of the view to display additional content or options. It typically allows users to easily access important information without disrupting their current workflow. Slide overs are mostly used to reveal opions for an entity.

Props

is-closeable?: boolean
If the slide-over can be closed with the escape key.

view-key?: string
A unique key to identify the current view within the slide over. Used for view-based transitions.

Emits

close: []
Triggered when the slide over is closed.

Slots

default
The content of the slide over.

Examples

Basic

A basic slide over.

<template>
    <FluxSecondaryButton
        icon-leading="arrow-left-to-line"
        label="Open"
        @click="isSlideOverOpened = true"/>

    <FluxSlideOver>
        <FluxPane v-if="isSlideOverOpened">
            <FluxPaneHeader title="Slide over">
                <FluxSecondaryButton
                    icon-before="xmark"
                    @click="isSlideOverOpened = false"/>
            </FluxPaneHeader>

            <FluxPaneBody>
                <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ab beatae dolore et ex facere itaque iusto labore minima, neque repellat sint vitae. Adipisci aliquid deserunt ea itaque laudantium quaerat sequi!</p>
                <p>Atque beatae delectus dolor ducimus eius officiis reprehenderit! Accusamus accusantium ex laudantium libero magnam minus numquam odio pariatur, perferendis quisquam veritatis voluptates. Aperiam, autem temporibus! Dolore harum nesciunt odit rem.</p>
                <p>Assumenda error illum, necessitatibus nihil provident ratione repellat repudiandae vero. Eius eveniet ex hic id incidunt molestiae perspiciatis quaerat quidem sed ullam. Aut cumque delectus laborum minima sunt voluptas voluptatibus?</p>
            </FluxPaneBody>

            <FluxPaneFooter>
                <FluxSecondaryButton
                    label="Close"
                    @click="isSlideOverOpened = false"/>

                <FluxSpacer/>

                <FluxPrimaryButton
                    icon-before="circle-check"
                    label="Save"
                    @click="isSlideOverOpened = false"/>
            </FluxPaneFooter>
        </FluxPane>
    </FluxSlideOver>
</template>

<script
    setup
    lang="ts">
    import { FluxPane, FluxPaneBody, FluxPaneFooter, FluxPaneHeader, FluxPrimaryButton, FluxSecondaryButton, FluxSlideOver, FluxSpacer } from '@flux-ui/components';
    import { ref } from 'vue';

    const isSlideOverOpened = ref(false);
</script>

Tabs

A slide over with tabs.

<template>
    <FluxSecondaryButton
        icon-leading="arrow-left-to-line"
        label="Open"
        @click="isSlideOverOpened = true"/>

    <FluxSlideOver>
        <FluxPane v-if="isSlideOverOpened">
            <FluxPaneHeader title="Slide over">
                <FluxSecondaryButton
                    icon-before="xmark"
                    @click="isSlideOverOpened = false"/>
            </FluxPaneHeader>

            <FluxTabs>
                <template #tabs="{ modelValue, tabs, activate }">
                    <FluxTabBar>
                        <template
                            v-for="(tab, index) in tabs"
                            :key="index">
                            <FluxTabBarItem
                                :icon="tab.icon"
                                :is-active="modelValue === index"
                                :label="tab.label"
                                @click="activate(index)"/>
                        </template>
                    </FluxTabBar>
                </template>

                <FluxTab label="Common">
                    <FluxPaneBody>
                        Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aliquam aliquid aperiam earum facilis fugiat in, itaque laboriosam, libero molestias nulla, pariatur qui quod sequi sint totam? Fuga ipsum placeat unde.
                    </FluxPaneBody>
                </FluxTab>

                <FluxTab label="Advanced">
                    <FluxPaneBody>
                        Lorem ipsum dolor sit amet, consectetur adipisicing elit. Animi consequatur dolorem dolorum ducimus enim, fuga, hic illo labore libero, magnam minima odio pariatur porro quasi quidem quis repellat reprehenderit vero?
                    </FluxPaneBody>
                </FluxTab>
            </FluxTabs>

            <FluxPaneFooter>
                <FluxSecondaryButton
                    label="Close"
                    @click="isSlideOverOpened = false"/>

                <FluxSpacer/>

                <FluxPrimaryButton
                    icon-before="circle-check"
                    label="Save"
                    @click="isSlideOverOpened = false"/>
            </FluxPaneFooter>
        </FluxPane>
    </FluxSlideOver>
</template>

<script
    setup
    lang="ts">
    import { FluxPane, FluxPaneBody, FluxPaneFooter, FluxPaneHeader, FluxPrimaryButton, FluxSecondaryButton, FluxSlideOver, FluxSpacer, FluxTab, FluxTabBar, FluxTabBarItem, FluxTabs } from '@flux-ui/components';
    import { ref } from 'vue';

    const isSlideOverOpened = ref(false);
</script>

Router-driven

Pair the slide over with Vue Router to open detail views through navigation. Define an over named view on every route that should appear inside the slide over, and render a single <RouterView name="over"/> from your top-level layout.

The layout watches route.matched for the first record that exposes the over view. When such a record is matched the <RouterView> renders inside the slide over; otherwise the slide over stays empty and the transition closes it. The matched route's fullPath is forwarded to the view-key prop so transitions are scoped to the active resource.

vue
<template>
    <RouterView/>

    <FluxSlideOver :view-key="slideOverRoute?.fullPath">
        <RouterView
            v-if="slideOverRoute"
            name="over"
            :route="slideOverRoute"/>
    </FluxSlideOver>
</template>

<script
    lang="ts"
    setup>
    import { FluxSlideOver } from '@flux-ui/components';
    import { computed } from 'vue';
    import { useRoute } from 'vue-router';

    const route = useRoute();

    const slideOverRoute = computed(() => {
        const match = route.matched.find(record => 'over' in (record.components ?? {}));

        if (!match) {
            return null;
        }

        return route;
    });
</script>
ts
import { createRouter, createWebHistory, type RouteRecordRaw } from 'vue-router';

const routes: RouteRecordRaw[] = [
    {
        path: '/orders',
        component: () => import('./views/Orders.vue'),
        children: [
            {
                name: 'order',
                path: ':id',
                components: {
                    over: () => import('./views/Order.vue')
                },
                children: [
                    {
                        name: 'order-buyer',
                        path: 'buyer',
                        component: () => import('./views/OrderBuyer.vue')
                    },
                    {
                        name: 'order-payment',
                        path: 'payment',
                        component: () => import('./views/OrderPayment.vue')
                    }
                ]
            }
        ]
    }
];

export const router = createRouter({
    history: createWebHistory(),
    routes
});

TIP

Push to one of the named routes (e.g. router.push({name: 'order', params: {id: 42}})) to open the slide over, and call router.back() from inside it to close. The slide over also supports nested children (such as tabs), each with their own URL.