Menu contextuel VContextMenu ouvre un menu au pointeur sur un clic droit, un appui long sous Android, la touche Menu ou Maj+F10. Son slot menu reçoit target, l’élément sur lequel le menu a été ouvert : un seul menu sert toute une liste.
Utilisation Right-click a file, or focus it and press Shift+F10.
<script setup lang="ts">
import { ref } from 'vue'
import { VContextMenu, VMenuItem, VMenuSeparator, VTypography } from 'vectis-ui'
const files = ['report.pdf', 'budget.xlsx', 'notes.txt']
const last = ref('')
function run(command: string, target: Element | null) {
const file = target?.closest<HTMLElement>('[data-file]')?.dataset.file
last.value = file ? `${command} ${file}` : command
}
</script>
<template>
<div class="column">
<VContextMenu as="ul" class="files" aria-label="Files">
<li v-for="file in files" :key="file" :data-file="file">
<button type="button" class="file">{{ file }}</button>
</li>
<template #menu="{ target }">
<VMenuItem label="Open" @select="run('Open', target)" />
<VMenuItem label="Rename" @select="run('Rename', target)" />
<VMenuSeparator />
<VMenuItem label="Delete" tone="danger" @select="run('Delete', target)" />
</template>
</VContextMenu>
<VTypography variant="body-sm" tone="muted">
{{ last ? `Last command: ${last}.` : 'Right-click a file, or focus it and press Shift+F10.' }}
</VTypography>
</div>
</template>
<style scoped>
.column {
display: grid;
gap: var(--vectis-space-3);
}
.files {
display: grid;
gap: var(--vectis-space-1);
max-inline-size: 20rem;
margin: 0;
padding: var(--vectis-space-2);
border: 1px dashed var(--vectis-color-border);
border-radius: var(--vectis-radius-md);
list-style: none;
}
.file {
inline-size: 100%;
padding: var(--vectis-space-2);
border: none;
border-radius: var(--vectis-radius-sm);
background: var(--vectis-color-surface-muted);
color: var(--vectis-color-text);
font: inherit;
text-align: start;
}
</style> Exemples Les commandes sont des items de VMenu : groupes, séparateurs, sous-menus, size et compact fonctionnent de la même façon. Près d’un bord de l’écran, le menu se retourne pour rester visible.
<script setup lang="ts">
import { VContextMenu, VMenuItem, VMenuSeparator } from 'vectis-ui'
</script>
<template>
<VContextMenu class="zone" tabindex="0">
Right-click this area.
<template #menu>
<VMenuItem label="Paste" />
<VMenuItem label="Sort by">
<template #submenu>
<VMenuItem label="Name" selected />
<VMenuItem label="Date modified" />
<VMenuItem label="Size" />
</template>
</VMenuItem>
<VMenuSeparator />
<VMenuItem label="New folder" />
</template>
</VContextMenu>
</template>
<style scoped>
.zone {
display: grid;
place-items: center;
min-block-size: 8rem;
border: 1px dashed var(--vectis-color-border);
border-radius: var(--vectis-radius-md);
color: var(--vectis-color-text-muted);
}
</style> Maj avec un clic droit affiche le menu du navigateur. disabled lui rend toute la zone.
<script setup lang="ts">
import { ref } from 'vue'
import { VContextMenu, VMenuItem, VSwitch } from 'vectis-ui'
const disabled = ref(false)
</script>
<template>
<div class="column">
<VSwitch v-model="disabled" label="Use the browser's menu" />
<VContextMenu :disabled="disabled" class="zone" tabindex="0">
Right-click this area, with or without Shift.
<template #menu>
<VMenuItem label="Copy" />
<VMenuItem label="Paste" />
</template>
</VContextMenu>
</div>
</template>
<style scoped>
.column {
display: grid;
gap: var(--vectis-space-3);
}
.zone {
display: grid;
place-items: center;
min-block-size: 8rem;
border: 1px dashed var(--vectis-color-border);
border-radius: var(--vectis-radius-md);
color: var(--vectis-color-text-muted);
}
</style> Savoir s’il est ouvert v-model:open suit chaque ouverture et fermeture. Ouvert par le code, le menu apparaît sous l’élément focalisé de la zone, ou sous la zone elle-même. Rendez aussi chaque commande accessible autrement, par un bouton visible par exemple : Safari sur iOS n’a pas de menu à l’appui long, et rien ne signale au lecteur que le menu existe.
Open from code The menu is closed.
<script setup lang="ts">
import { ref } from 'vue'
import { VButton, VContextMenu, VMenuItem, VTypography } from 'vectis-ui'
const open = ref(false)
</script>
<template>
<div class="column">
<VContextMenu v-model:open="open" class="zone" tabindex="0">
Right-click this area.
<template #menu>
<VMenuItem label="Copy" />
<VMenuItem label="Paste" />
</template>
</VContextMenu>
<div class="row">
<VButton variant="ghost" tone="neutral" @click="open = true">Open from code</VButton>
<VTypography variant="body-sm" tone="muted">
The menu is {{ open ? 'open' : 'closed' }}.
</VTypography>
</div>
</div>
</template>
<style scoped>
.column {
display: grid;
gap: var(--vectis-space-3);
}
.row {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--vectis-space-3);
}
.zone {
display: grid;
place-items: center;
min-block-size: 8rem;
border: 1px dashed var(--vectis-color-border);
border-radius: var(--vectis-radius-md);
color: var(--vectis-color-text-muted);
}
</style> API Props Slots