Menu
Basic
AMenu
allows creating menu with various options to customize the behavior.
<script lang="ts" setup>
const items = [
{ text: 'Donut jujubes' },
{ text: 'Sesame snaps' },
{ text: 'I love jelly' },
{ text: 'Cake gummi', disable: true },
]
</script>
<template>
<ABtn>
<AMenu>
<AList :items="items" />
</AMenu>
Open Menu
</ABtn>
</template>
Trigger
To open menu on hover use set trigger
prop to hover
.
<script lang="ts" setup>
const items = [
{ text: 'Donut jujubes' },
{ text: 'Sesame snaps' },
{ text: 'I love jelly' },
{ text: 'Cake gummi', disable: true },
]
</script>
<template>
<ABtn>
<AMenu trigger="hover">
<AList :items="items" />
</AMenu>
Open Menu
</ABtn>
</template>
v-model support
AMenu
also support v-model
to show/hide menu.
<script lang="ts" setup>
import { ref } from 'vue'
const items = [
{ text: 'Donut jujubes' },
{ text: 'Sesame snaps' },
{ text: 'I love jelly' },
{ text: 'Cake gummi', disable: true },
]
const isMenuVisible = ref(false)
</script>
<template>
<div class="flex flex-wrap gap-12">
<ABtn>
<AMenu v-model="isMenuVisible">
<AList :items="items" />
</AMenu>
Button
</ABtn>
<div class="flex flex-wrap gap-4">
<ABtn
variant="light"
@click="isMenuVisible = true"
>
Open Menu
</ABtn>
<ABtn
variant="light"
@click="isMenuVisible = false"
>
Close Menu
</ABtn>
</div>
</div>
</template>
Persistence
Use persist
prop to adjust the persistence of menu.
Default value is false
, it will close the menu on any click. Set it to true
to persist it on outside click. You can use persist="content"
to persist menu to content only, means if you click on content menu won't close however outside click of content will close the menu.
<script lang="ts" setup>
const items = [
{ text: 'Donut jujubes' },
{ text: 'Sesame snaps' },
{ text: 'I love jelly' },
{ text: 'Cake gummi', disable: true },
]
</script>
<template>
<div class="flex flex-wrap gap-4">
<ABtn>
<AMenu persist>
<AList :items="items" />
</AMenu>
Persist
</ABtn>
<ABtn>
<AMenu persist="content">
<AList :items="items" />
</AMenu>
Content Persist
</ABtn>
</div>
</template>
Transition
AMenu
also support transition. Default transition is slide-y
. Set it to available transition to use different transition. e.g. transition="fade"
.
To disable the transition you can set transition
prop to null
.
<script lang="ts" setup>
const items = [
{ text: 'Donut jujubes' },
{ text: 'Sesame snaps' },
{ text: 'I love jelly' },
{ text: 'Cake gummi', disable: true },
]
</script>
<template>
<ABtn>
<AMenu :transition="null">
<AList :items="items" />
</AMenu>
Open Menu
</ABtn>
</template>
Placement
As AMenu
uses Floating UI, you can configure how menu is rendered.
To adjust the placement of menu, use placement
prop. This will get directly passed to Floating UI as show in their docs.
✨ Auto Placement
If there's not enough space to render the menu on given position then it will update the position according to available space.
<script lang="ts" setup>
import type { Placement } from '@floating-ui/vue'
import { useCycleList } from '@vueuse/core'
const items = [
{ text: 'Donut jujubes' },
{ text: 'Sesame snaps' },
{ text: 'I love jelly' },
{ text: 'Cake gummi', disabled: true },
]
const placementOptions: Placement[] = [
'top',
'top-start',
'top-end',
'right',
'right-start',
'right-end',
'bottom',
'bottom-start',
'bottom-end',
'left',
'left-start',
'left-end',
]
const { state: menuPlacement, next: selectNext } = useCycleList(placementOptions)
</script>
<template>
<div class="flex items-center flex-wrap gap-4 mb-38">
<ABtn>
<AMenu
:model-value="true"
:placement="menuPlacement"
>
<AList :items="items" />
</AMenu>
Open Menu
</ABtn>
<!-- 👉 Options -->
<ASelect
v-model="menuPlacement"
:options="placementOptions"
class="w-24 grow-0 ms-auto"
/>
<ABtn
variant="text"
@click="selectNext"
>
Next
</ABtn>
</div>
</template>
Strategy
Set which positioning strategy to use to render the menu. This is also Floating UI option, for more details please read the official docs here.
<script lang="ts" setup>
const items = [
{ text: 'Donut jujubes' },
{ text: 'Sesame snaps' },
{ text: 'I love jelly' },
{ text: 'Cake gummi', disable: true },
]
</script>
<template>
<ABtn>
<AMenu strategy="fixed">
<AList :items="items" />
</AMenu>
Open Fixed Menu
</ABtn>
</template>
Middleware
AMenu
has some middleware as default to render the menu content correctly. You can also customize the middleware you want.
In below demo we are not using any middleware so menu component won't behave like above menu contents. e.g. Flipping menu content if there's not enough space won't work.
middleware
prop accepts function that must return array of middleware. Please refer to the code snippet of this demo for function signature.
You can read more about middleware on their official docs.
<script lang="ts" setup>
import type { AFloatingMiddlewareFunc } from 'anu-vue'
const items = [
{ text: 'Donut jujubes' },
{ text: 'Sesame snaps' },
{ text: 'I love jelly' },
{ text: 'Cake gummi', disable: true },
]
const middleware: AFloatingMiddlewareFunc = (referenceEl, floatingEl) => {
// console.log('referenceEl :>> ', referenceEl)
// console.log('floatingEl :>> ', floatingEl)
// We aren't adding any middleware
return []
}
</script>
<template>
<ABtn>
<AMenu :middleware="middleware">
<AList :items="items" />
</AMenu>
Open Menu
</ABtn>
</template>
API
Show/Hide floating element base on v-model value
Persistence of floating element when clicked outside of reference element
Trigger event to open the floating element
Delay before showing floating element
Delay before hiding floating element
Transition to add while showing/hiding floating element
Placement option from Floating UI
Strategy option from Floating UI
Middleware option from Floating UI
Default slot for rendering menu content
Generally, you will use AList
component here.