a vue 3 drop down component that uses <ul> and <li> to mimic a native browser dropdown select, with all required keyboard and accessibility standards in typescript

Here's an example implementation of a Vue 3 dropdown component inspired by the a11y_dropdown project:

First, we'll declare an interface for the options.

index.ts
interface DropdownOption {
  label: string;
  value: any;
}
60 chars
5 lines

Next, we'll create the component in its simplest form, with props for the options and selected value.

<template>
  <div class="dropdown">
    <button
      class="dropdown-toggle"
      aria-haspopup="true"
      aria-expanded="false"
      @click="open = !open"
    >
      {{ selectedOption.label }}
    </button>
    <ul
      v-show="open"
      class="dropdown-menu"
      aria-labelledby="dropdownButton"
      @keydown.enter.stop.prevent="selectOption"
      @keydown.escape="closeDropdown"
    >
      <li
        v-for="(option, index) in options"
        :key="index"
        :class="{ 'dropdown-item': true, active: option.value === selectedOption.value }"
        @mousedown.stop.prevent="selectOption(option)"
      >
        {{ option.label }}
      </li>
    </ul>
  </div>
</template>

<script lang="ts">
import { defineComponent, ref } from "vue";

interface DropdownOption {
  label: string;
  value: any;
}

export default defineComponent({
  name: "Dropdown",
  props: {
    options: {
      type: Array as () => DropdownOption[],
      required: true,
    },
    value: {
      type: [Object, String, Number, Boolean],
      required: true,
    },
  },
  emits: ["update:value"],
  setup(props, { emit }) {
    const open = ref(false);
    const selectedOption = computed(() =>
      props.options.find((option) => option.value === props.value)
    );

    function selectOption(option: DropdownOption) {
      emit("update:value", option.value);
      open.value = false;
    }

    function closeDropdown() {
      open.value = false;
    }

    return {
      open,
      selectedOption,
      selectOption,
      closeDropdown,
    };
  },
});
</script>
1577 chars
75 lines

This component makes use of several accessibility features:

  • ARIA attributes to describe the dropdown
  • keyboard event listeners for opening and closing the dropdown, selecting an option, and navigating the list
  • CSS classes to indicate the selected option and active/hovered option

Note that this implementation assumes that the button will always be present and visible on the page. If the button is hidden or removed from the DOM, the dropdown will not be accessible.

gistlibby LogSnag