funkwhale/front/ui-docs/components/ui/popover.md

18 KiB

Popover (Dropdown Menu)

Popovers (Popover) are dropdown menus activated by a button. Use popovers to create dropdown menus ranging from simple lists to complex nested menus.

Common uses:

  • "More actions" dropdown menus
  • Navigation menus
  • Settings menus
  • Context menus (right-click menus)
Prop Data type Required? Description
open Boolean No Controls whether the popover is open. Defaults to false.

Options button

The options button (OptionsButton) is a stylized button you can use to hide and show your popover. Use Vue event handling to map the button to a boolean value.

<script setup lang="ts">
  const open = ref(false)
</script>

<template>
  <Popover v-model:open="open">
    <OptionsButton @click="open = !open" />
  </Popover>
</template>

You can also use the toggleOpen prop in the <template #default> tag if you prefer not to use refs to control the menu's visibility.

<script setup lang="ts">
const open = ref(false)
const privacyChoices = ['pod', 'public', 'private']
const bcPrivacy = ref('pod')
</script>

<template>
  <Popover v-model:open="isOpen">
    <template #default="{ toggleOpen }">
      <Pill
      @click="(e) => {
        console.log('Pill clicked');
        console.log('Before toggleOpen:', isOpen);
        toggleOpen();
        console.log('After toggleOpen:', isOpen);
      }"
        :blue="bcPrivacy === 'pod'"
        :red="bcPrivacy === 'public'"
      >
        {{ bcPrivacy }}
      </Pill>
    </template>
    <template #items>
      <PopoverRadio v-model="bcPrivacy" :choices="privacyChoices"/>
    </template>
  </Popover>
</template>
{{ bcPrivacy }}

Items

Popovers contain a list of menu items. Items can contain different information based on their type.

::: info Lists of items must be nested inside a <template #items> tag directly under the <Popover> tag. :::

Popover item

The popover item (PopoverItem) is a simple button that uses Vue event handling. Each item contains a slot which you can use to add a menu label and icon.

<script setup lang="ts">
  const alert = (message: string) => window.alert(message)
  const open = ref(false)
</script>

<template>
  <Popover v-model:open="open">
    <OptionsButton @click="open = !open" />
    <template #items>
      <PopoverItem @click="alert('Report this object?')">
        <i class="bi bi-exclamation" />
        Report
      </PopoverItem>
    </template>
  </Popover>
</template>
Report

Checkbox

The checkbox (PopoverCheckbox) is an item that acts as a selectable box. Use v-model to bind the checkbox to a boolean value. Each checkbox contains a slot which you can use to add a menu label.

<script setup lang="ts">
const bc = ref(false)
const cc = ref(false)
const open = ref(false)
</script>

<template>
  <Popover v-model:open="open">
    <OptionsButton @click="open = !open" />
    <template #items>
      <PopoverCheckbox v-model="bc">
        Bandcamp
      </PopoverCheckbox>
      <PopoverCheckbox v-model="cc">
        Creative commons
      </PopoverCheckbox>
    </template>
  </Popover>
</template>
Bandcamp Creative commons

Radio

The radio (PopoverRadio) is an item that acts as a radio selector.

Prop Data type Required? Description
modelValue String Yes The current value of the radio. Use v-model to bind this to a value.
choices Array<String> Yes A list of choices.
<script setup lang="ts">
const open = ref(false);
const currentChoice = ref("pod");
const privacy = ["public", "private", "pod"];
</script>

<template>
  <Popover v-model:open="open">
    <OptionsButton @click="open = !open" />
    <template #items>
      <PopoverRadio v-model="currentChoice" :choices="choices" />
    </template>
  </Popover>
</template>

Separator

Use a standard horizontal rule (<hr>) to add visual separators to popover lists.

<script setup lang="ts">
const bc = ref(false)
const cc = ref(false)
const open = ref(false)
</script>

<template>
  <Popover v-model:open="open">
    <OptionsButton @click="open = !open" />
    <template #items>
      <PopoverCheckbox v-model="bc">
        Bandcamp
      </PopoverCheckbox>
      <hr>
      <PopoverCheckbox v-model="cc">
        Creative commons
      </PopoverCheckbox>
    </template>
  </Popover>
</template>
Bandcamp
Creative commons

Submenus

To create more complex menus, you can use submenus (PopoverSubmenu). Submenus are menu items which contain other menu items.

<script setup lang="ts">
const bc = ref(false)
const open = ref(false)
</script>

<template>
  <Popover v-model:open="open">
    <OptionsButton @click="open = !open" />
    <template #items>
      <PopoverSubmenu>
        <i class="bi bi-collection" />
        Organize and share
        <template #items>
          <PopoverCheckbox v-model="bc">
            Bandcamp
          </PopoverCheckbox>
        </template>
      </PopoverSubmenu>
    </template>
  </Popover>
</template>
Organize and share Bandcamp

Extra items

You can add extra items to the right hand side of a popover item by nesting them in a <template #after> tag. Use this to add additional menus or buttons to menu items.

<script setup lang="ts">
const bc = ref(false)
const privacyChoices = ['public', 'private', 'pod']
const bcPrivacy = ref('pod')
const open = ref(false)
</script>

<template>
  <Popover v-model:open="open">
    <OptionsButton @click="open = !open" />
    <template #items>
      <PopoverSubmenu>
        <i class="bi bi-collection" />
        Organize and share
        <template #items>
          <PopoverCheckbox v-model="bc">
            Bandcamp
            <template #after>
              <Popover>
                <template #default="{ toggleOpen }">
                  <Pill @click.stop="toggleOpen" :blue="bcPrivacy === 'pod'" :red="bcPrivacy === 'public'">
                    {{ bcPrivacy }}
                  </Pill>
                </template>
                <template #items>
                  <PopoverRadio v-model="bcPrivacy" :choices="privacyChoices"/>
                </template>
              </Popover>
            </template>
          </PopoverCheckbox>
          <hr>
          <PopoverCheckbox v-model="share">
            Share by link
            <template #after>
              <Button @click.stop="alert('Link copied to clipboard')" color="secondary" round icon="bi-link" />
              <Button @click.stop="alert('Here is your code')" color="secondary" round icon="bi-code" />
            </template>
          </PopoverCheckbox>
        </template>
      </PopoverSubmenu>
    </template>
  </Popover>
</template>
Organize and share Bandcamp {{ bcPrivacy }}
Share by link

Menu

Here is an example of a completed menu containing all supported features.

<script setup lang="ts">
const open = ref(false);
const bc = ref(false);
const cc = ref(false);
const share = ref(false);
const bcPrivacy = ref("pod");
const ccPrivacy = ref("public");
const privacyChoices = ["private", "pod", "public"];
</script>

<template>
  <Popover v-model:open="open">
    <OptionsButton @click="open = !open" />
    <template #items>
      <PopoverItem>
        <i class="bi bi-arrow-up-right" />
        Play next
      </PopoverItem>
      <PopoverItem>
        <i class="bi bi-arrow-down-right" />
        Append to queue
      </PopoverItem>
      <PopoverSubmenu>
        <i class="bi bi-music-note-list" />
        Add to playlist
        <template #items>
          <PopoverItem>
            <i class="bi bi-music-note-list" />
            Sample playlist
          </PopoverItem>
          <hr />
          <PopoverItem>
            <i class="bi bi-plus-lg" />
            New playlist
          </PopoverItem>
        </template>
      </PopoverSubmenu>
      <hr />
      <PopoverItem>
        <i class="bi bi-heart" />
        Add to favorites
      </PopoverItem>
      <PopoverSubmenu>
        <i class="bi bi-collection" />
        Organize and share
        <template #items>
          <PopoverCheckbox v-model="bc">
            Bandcamp
            <template #after>
              <Popover>
                <template #default="{ toggleOpen }">
                  <Pill
                    @click.stop="toggleOpen"
                    :blue="bcPrivacy === 'pod'"
                    :red="bcPrivacy === 'public'"
                  >
                    {{ bcPrivacy }}
                  </Pill>
                </template>
                <template #items>
                  <PopoverRadio v-model="bcPrivacy" :choices="privacyChoices" />
                </template>
              </Popover>
            </template>
          </PopoverCheckbox>
          <PopoverCheckbox v-model="cc">
            Creative Commons
            <template #after>
              <Popover v-model:open="isOpen">
                <template #default="{ toggleOpen }">
                  <Pill
                    @click="toggleOpen"
                    :blue="ccPrivacy === 'pod'"
                    :red="ccPrivacy === 'public'"
                  >
                    {{ ccPrivacy }}
                  </Pill>
                </template>
                <template #items>
                  <PopoverRadio v-model="ccPrivacy" :choices="privacyChoices" />
                </template>
              </Popover>
            </template>
          </PopoverCheckbox>
          <hr />
          <PopoverItem>
            <i class="bi bi-plus-lg" />
            New library
          </PopoverItem>
          <hr />
          <PopoverCheckbox v-model="share">
            Share by link
            <template #after>
              <Button @click.stop color="secondary" round icon="bi-link" />
              <Button @click.stop color="secondary" round icon="bi-code" />
            </template>
          </PopoverCheckbox>
        </template>
      </PopoverSubmenu>
      <PopoverItem>
        <i class="bi bi-cloud-download" />
        Download
      </PopoverItem>
      <hr />
      <PopoverItem>
        <i class="bi bi-exclamation" />
        Report
      </PopoverItem>
    </template>
  </Popover>
</template>
Play next Append to queue Add to playlist Sample playlist
New playlist

Add to favorites Organize and share Bandcamp {{ bcPrivacy }} Creative Commons {{ ccPrivacy }}
New library
Share by link
Download
Report