Popup
A Popup is a modal window with isolated interaction from the main application. It can be shown programmatically and hidden through user interaction.
Demo
Usage
Popup backdrop
In order to display popups as modal windows, the popup boolean prop must be passed to the Vergil component.
<script setup>
import { Vergil } from '@8ctavio/vergil/components'
</script>
<template>
<Vergil popup>
<AppLayout/>
</Vergil>
</template>TIP
The popups' backdrop z-index value is by default set to 10 through a css variable. See Styles on the Get Started guide to learn how to overwrite Vergil's css variables.
Popup components
A popup component is any SFC with a Popup component as its root component.
<!-- @/components/popups/PopupComponent.vue -->
<script setup>
import { Popup } from '@8ctavio/vergil/components'
</script>
<template>
<Popup title="Custom Popup">
<!-- Popup content... -->
</Popup/>
</template>TIP
Create popup components inside a components/popups directory.
Show Popup
A popup component can be displayed programmatically with the showPopup function. It receives an imported popup component object.
import PopupComponent from '@/components/popups/PopupComponent.vue'
import { showPopup } from '@8ctavio/vergil'
showPopup(PopupComponent)WARNING
The Popup component traps application focus; therefore, popup components should only be mounted using the showPopup function.
Change Popup
The showPopup function can be called inside a popup component. This results in the open popup component being replaced with the one specified in showPopup.
In the following demo, two popup components have a button to change between components.
Popup props and events
The showPopup function receives two parameters. First one is the popup component object, i.e., the popup to show. The second is an object with prop values and event handlers for props and events defined in the popup component.
Thus, defineProps and defineEmits should be normally used in a popup component for two-way communication between the component and the API (showPopup).
<!-- @/components/popups/PopupComponent.vue -->
<script setup>
defineProps({
// Define data required by the popup
})
defineEmits([/* Define events to be handled by the API */])
</script>The keys of the object sent through showPopup should be
- for props: the prop key as defined in the
definePropsdirective. - for events: the Pascal-case version of the event name as defined in the
defineEmitsdirective, prefixed withon.
For example, if the following props and events are defined in the popup component
defineProps(['foo', 'bar'])
defineEmits(['baz'])the following props object can be sent with showPopup
showPopup(PopupComponent, {
foo: '',
bar: 0,
onBaz(){}
})Close Popup
A popup component may be closed by the user through the Popup close button in the top-right corner or programmatically by emitting a close or error event from the popup component.
<!-- @/components/popups/PopupComponent.vue -->
<script setup>
const emit = defineEmits(['close', 'error'])
// ...later
emit('close') // or emit('error')
</script>Despite these events being used internally to close the popup, event handlers can still be attached to each.
showPopup(PopupComponent, {
onClose(){}
onError(){}
})Closing the popup through the close button will call the onClose handler.
Autofocus
By default, the popup component's first tabbable element is focused when mounted, but this behavior can be modified by passing an autofocus prop to the Popup component.
The autofocus prop may be a boolean, an HTMLElement object, or a ComponentPublicInstance, and its default value is true.
- If
autofocus === false: No popup component child is focused (to keep focus trapped, the popup component's root element itself is focused). - If
autofocus instanceof HTMLElement: The element's first tabbable element (including itself) is focused. - If
autofocusis aComponentPublicInstance: The instance$elelement's first tabbable element (including itself) is focused.
<script setup>
const autofocus = useTemplateRef('autofocus')
</script>
<template>
<Popup title="Custom autofocus" :autofocus>
<main class="popup-content">
<InputText placeholder="First tabbable element"/>
<InputText :ref="autofocus" placeholder="Force autofocus"/>
</main>
</Popup>
</template>Popup content
The recommended practice to define Popup content, is to add a main.popup-content element inside the Popup's default slot. Popup's content layout and styles can be defined by styling the .popup-content element.
<template>
<Popup title="Some title">
<main class="popup-content">
<!-- content... -->
</main>
</Popup>
</template>
<style scoped>
.popup-content {
/* define content layout, padding, background color, etc. */
}
</style>API Reference
showPopup
function showPopup(component: Component, props: object): voidParameters
component: A component object.props: Props object appended tocomponentvia thev-binddirective.
Props
| prop | type | default |
|---|---|---|
title | string | |
disabled | boolean | |
theme | 'brand' | 'user' | 'ok' | 'info' | 'warn' | 'danger' | 'neutral' | 'brand' |
size | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'md' |
radius | 'none' | 'sm' | 'md' | 'lg' | 'full' | 'md' |
Configuration options
Popup's configuration options allow to overwrite some Popup props' default values and may be overwritten under the popup root-level configuration option.
popup.<option> | type | default | global |
|---|---|---|---|
theme | theme | ✅ | |
size | size | ✅ | |
radius | radius | ✅ |
Styling
To properly display the popup component, (commonly) its width property needs to be styled. It's recommended to use the clamp function for the width, with min and max values expressed in pixels (px) and val expressed as a percentage (%).
An example of recommended styles is shown below. clamp values should be adjusted depending on the popup's content.
<template>
<Popup>
<main class="popup-content"></main>
</Popup>
</template>
<style scoped>
.popup {
width: clamp(250px, 25%, 400px);
}
.popup-content {
box-sizing: border-box;
width: 100%;
padding: 25px;
}
</style>Popup template
<script setup>
import { Popup } from '@8ctavio/vergil/components'
defineProps({
})
const emit = defineEmits(['close', 'error'])
</script>
<template>
<Popup title="">
<main class="popup-content">
</main>
</Popup>
</template>
<style scoped>
.popup {
width: clamp(250px, 30%, 800px);
}
.popup-content {
box-sizing: border-box;
width: 100%;
padding: 25px;
}
</style>