Skip to content

Overlay

Overlays can be used to reveal larger contents or options that are hidden behind a button or a similar component. The content is animated on top of the document and the rest of the interface is blocked.

Props

is-closeable?: boolean
If the overlay is closeable with the escape key.

size?: FluxSize
The size of the overlay.
Default: small

Emits

close: []
Emitted when the overlay is closed.

Slots

default
The contents of the overlay. For the best result, use a with a v-if to control its visibility.

Examples

Basic

A basic overlay.

<template>
    <FluxSecondaryButton
        icon-leading="copy"
        label="Open overlay"
        @click="isOpen = true"/>

    <FluxOverlay size="medium">
        <FluxPane v-if="isOpen">
            <FluxPaneHeader title="Overlay"/>

            <FluxPaneBody>
                <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aliquam aspernatur, consequuntur debitis eligendi eum magnam necessitatibus nulla perferendis sequi voluptate. Aut consequatur ducimus, quaerat quos ratione sequi veniam? Quis, rem.</p>
                <p>Alias dolorum laboriosam pariatur qui ut. Debitis distinctio expedita impedit ipsam voluptatem? Asperiores assumenda dolorem ducimus earum nam placeat ut velit. Ab debitis dicta in itaque quos ut veritatis voluptatum.</p>
                <p>Ducimus nemo officiis, quas saepe sequi tempora unde! Debitis dolores eos exercitationem itaque laboriosam magni nam, neque officiis, pariatur quis ratione recusandae reiciendis repudiandae tempore temporibus veritatis vero, voluptates? Earum?</p>
            </FluxPaneBody>

            <FluxPaneFooter>
                <FluxSecondaryButton
                    label="Close"
                    @click="isOpen = false"/>
            </FluxPaneFooter>
        </FluxPane>
    </FluxOverlay>
</template>

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

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

Re-authenticatie

A re-authentication overlay.

<template>
    <FluxDestructiveButton
        icon-leading="lock"
        label="Re-authenticate"
        @click="isOpen = true"/>

    <FluxOverlay size="small">
        <FluxPane v-if="isOpen">
            <FluxForm>

                <FluxPaneBody>
                    <h2>You've been signed out.</h2>
                </FluxPaneBody>

                <FluxPaneBody>
                    <p>To continue using your account, please sign in again using your password.</p>
                </FluxPaneBody>

                <FluxPaneBody>
                    <FluxFormColumn>
                        <FluxFormField label="Username">
                            <FluxFormInput type="email" model-value="bas@flux-ui.dev" disabled is-readonly/>
                        </FluxFormField>

                        <FluxFormField label="Password">
                            <FluxFormInput type="password" model-value="12345678"/>
                        </FluxFormField>
                    </FluxFormColumn>
                </FluxPaneBody>

                <FluxPaneFooter>
                    <FluxButtonStack
                        is-fill
                        direction="vertical">
                        <FluxPrimaryButton
                            icon-trailing="user-key"
                            label="Sign in"/>
                        <FluxSecondaryButton
                            label="Cancel"
                            @click="isOpen = false"/>
                    </FluxButtonStack>
                </FluxPaneFooter>
            </FluxForm>
        </FluxPane>
    </FluxOverlay>
</template>

<script
    setup
    lang="ts">
    import { FluxButtonStack, FluxDestructiveButton, FluxForm, FluxFormColumn, FluxFormField, FluxFormInput, FluxOverlay, FluxPane, FluxPaneBody, FluxPaneFooter, FluxPrimaryButton, FluxSecondaryButton } from '@flux-ui/components';
    import { ref } from 'vue';

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

Router-driven

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

The layout watches route.matched for the first record that exposes the overlay view. When such a record is matched the <RouterView> renders inside the overlay; otherwise the overlay stays empty and the transition closes it.

vue
<template>
    <RouterView/>

    <FluxOverlay
        :key="overlayRoute?.fullPath"
        size="medium">
        <RouterView
            v-if="overlayRoute"
            name="overlay"
            :route="overlayRoute"/>
    </FluxOverlay>
</template>

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

    const route = useRoute();

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

        if (!match) {
            return null;
        }

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

const routes: RouteRecordRaw[] = [
    {
        path: '/projects',
        component: () => import('./views/Projects.vue'),
        children: [
            {
                name: 'projects-create',
                path: 'create',
                components: {
                    overlay: () => import('./views/ProjectsCreate.vue')
                }
            },
            {
                name: 'projects-edit',
                path: 'edit/:id',
                components: {
                    overlay: () => import('./views/ProjectsEdit.vue')
                }
            }
        ]
    }
];

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

TIP

Push to one of the named routes (e.g. router.push({name: 'projects-create'})) to open the overlay, and call router.back() from inside the overlay to close it. This keeps the URL in sync with what's on screen and makes the overlay deep-linkable.