Raccourci clavier : Ctrl + K
Commencer

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

vue

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.

vue
Right-click this area.
<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>

Le menu du navigateur

Maj avec un clic droit affiche le menu du navigateur. disabled lui rend toute la zone.

vue
Right-click this area, with or without Shift.
<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.

vue
Right-click this area.

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

PropTypeDéfaut
asstring'div'
Élément qui enveloppe la zone.
sizeMenuSize'sm' | 'md' | 'lg''sm'
Taille des lignes, héritée par les sous-menus.
compactbooleanfalse
Réduit la hauteur des lignes, sous-menus compris.
widthnumber | stringaucune
Largeur du panneau. Un nombre est en pixels ; une chaîne, une longueur ou un mot-clé CSS.
disabledbooleanfalse
Laisse la zone au menu du navigateur.
v-model:openbooleanfalse
État d’ouverture, synchronisé avec les clics extérieurs, Échap et le choix d’une commande.

Slots

SlotType
default{}
Contenu de la zone.
menu{ target: Element | null; }
Enfants VMenuItem, VMenuGroup et VMenuSeparator. Reçoit target.