Wowerlay is a popover library for Vue 3 applications. It's powered by Floating UI
Wowerlay is created to work well with Vue. It wraps floating-ui
features with its own features like scoping
(See Demo/Scope), transitioning
(See Demo/Transitions) and mounting-unmounting vue components when popover visiblity changes.
You can see all examples Here.
For npm:
npm install wowerlay
For pnpm:
pnpm install wowerlay
For yarn:
yarn add wowerlay
First you need to import the stylesheet
.
import 'wowerlay/style.css';
import { createApp } from 'vue';
import App from './App.vue';
createApp(App).mount('#app');
Using wowerlay is simple, place it anywhere in your component (It will be teleported to body) and give target
and visible
props. Wowerlay will follow its target
when visible
is true otherwise it will not be mounted.
Wowerlay is just a div
element, any attribute that is not a Wowerlay prop will be passed as attribute to the element. Element tag can be changed by tag
prop.
<template>
<button
ref="targetElement"
@click="visible = !visible"
>
Show Popover?
</button>
<Wowerlay
tag="section"
:target="targetElement"
v-model:visible="visible"
>
<div>Hey how you doin?</div>
<button>Good</button>
<button>Bad</button>
</Wowerlay>
</template>
<script setup lang="ts">
import { Wowerlay } from 'wowerlay';
import { ref } from 'vue';
const targetElement = ref<HTMLElement>();
const visible = ref(false);
</script>
If you don't want to prevent attribute inheritance
you can use Wowerlay inside of an element, it'll be teleported
to body
.
<template>
<button
ref="targetElement"
@click="visible = !visible">
Show popover
<Wowerlay
tag="div"
:target="targetElement"
:visible="visible"
@update:visible="(value) => visible = value"
>
<div>Hey how you doin?</div>
<button>Good</button>
<button>Bad</button>
</Wowerlay>
</button>
</template>
Styling wowerlay is simple. <Wowerlay/>
is just a single wrapper element.
!! You shouldn't change necessary styles !!
<Wowerlay
tag="span"
style="width: 300px; height: 300px; display: inline-block"
>
Content Goes Here
</Wowerlay>
- You can set
--wowerlay-z
CSS parameter for Wowerlay z-index.
You can use TemplateRef to update position dynamically, this will ignore fixed prop.
<Wowerlay ref="wowerlayInstance">
Content Goes Here
</Wowerlay>
<script setup lang="ts">
import { WowerlayTemplateRef } from 'wowerlay'
const wowerlayInstance = ref<WowerlayTemplateRef>();
function updateSomeTime() {
wowerlayInstance.value?.update();
}
</script>
You can use #arrow
slot for custom arrows, Wowerlay will automatically get element from #arrow
slot but you shouldn't pass Fragments (multiple root components) to slot. Arrow slot must contain only one root element or a component that has only one root element, otherwise it won't work.
You can use side
(top, left, right, bottom) and placement
(left-start, righ-start, etc.) for styling your arrow depending on the side and placement.
You must add gap
prop to Wowerlay otherwise arrow will be on top of the target.
<template>
<!-- Gap same as arrow size -->
<Wowerlay :gap="10">
<template #default>
Content Goes Here
</template>
<template #arrow="{ side, placement }">
<div
class="my-arrow"
:class="{
'arrow-right': side === 'left',
'arrow-left': side === 'right',
'arrow-top': side === 'bottom',
'arrow-bottom': side === 'top',
}"
/>
</template>
</Wowerlay>
<!-- Or you can use a component -->
<Wowerlay :arrowPadding="5">
<template #default>
Content Goes Here
</template>
<template #arrow="{ side, placement }">
<MyArrow :side="side" :placement="placement" />
</template>
</Wowerlay>
</template>
interface WowerlayEmits {
/**
* Fires when wowerlay wants to change its visibility state.
*/
'update:visible': (visible: Boolean) => void;
/**
* Fires when Wowerlay element changes, this can be used to do some DOM stuff to Wowerlay popover element.
* Can be used as v-model:el
*/
'update:el': (element: HTMLElement | null) => void;
}
interface WowerlayProps {
/**
* Primary position for Wowerlay.
* @default "bottom"
*/
position?:
| 'left'
| 'left-start'
| 'left-end'
| 'right'
| 'right-start'
| 'right-end'
| 'top'
| 'top-start'
| 'top-end'
| 'bottom'
| 'bottom-start'
| 'bottom-end';
/**
* Target for Wowerlay to follow
*/
target: HTMLElement | VirtualElement;
/**
* If given, Wowerlay will be able to leave screen.
* @default false
*/
canLeaveViewport?: boolean;
/**
* If given Wowerlay won't update its position after mounted
* @default false
*/
fixed?: boolean;
/**
* If given Wowerlay will not flip to stay in view.
* @default false
*/
noFlip?: boolean;
/**
* Tag name for Wowerlay wrapper element.
* @default "div"
*/
tag?: string;
/**
* Gap between Wowerlay and the target.
* @default 0
*/
gap?: number;
/**
* Removes click blocker background when Wowerlay is visible
* @default false
*/
noBackground?: boolean;
/**
* Disable or set custom transition for Wowerlay
* @set string to use your own transition name.
* @set function to use a custom handler..
* @see "Demo/JS Transition"
*/
transition?: string | WowerlayTransitionFn;
/**
* If enabled Wowerlay will sync its placement bounds same as target's bounds.
* @default false
*/
syncSize?: boolean;
/**
* Any given attribute (except key) is passed to Wowerlay`s wrapper background element.
* @default {}
*/
backgroundAttrs?: {
// This means that do not pass a key it will be dropped.
key?: undefined | null;
ref?: ((element: HTMLDivElement) => void) | Ref<HTMLElement | null | undefined>;
[key: string]: any;
};
/**
* Custom middlewares for Floating-UI.
* @default {}
*/
middlewas?: Middleware[];
/**
* Padding value for floating-ui arrow middleware.
* @default 0
*/
arrowPadding?: number;
}
Wowerlay has two special attributes for managing close on click situations.
These attributes help users not to use stopPropagation
to control Wowerlay close mechanism.
-
data-wowerlay-scope
: If clicked element or any of its parent element has this attribute, only Wowerlay instances that is attached to any children of the scope element will close on click. -
data-wowerlay-stop
: If clicked element or any of its parent element has this attribute, Wowerlay will not fire close event. This is intended to be alternative ofstopPropagation
. -
See demo for examples.