# Glide Select

> Select chip whose menu pops from its corner and whose highlight glides between rows.

A compact select. Press the chip and the menu pops from its corner; one highlight pill glides from row to row as you hover. You can also press, drag down the list and release on an option in one gesture. The keyboard works like a native combobox, including type-ahead.

<demo-glide-select>



</demo-glide-select>

## Installation

```bash
npx shadcn-vue@latest add "https://nxui.geoql.in/r/glide-select.json"
```

## Usage

```vue
<script setup lang="ts">
  import { ref } from 'vue';
  import GlideSelect from '~/components/ui/glide-select/GlideSelect.vue';

  const format = ref('png');
  const formats = [
    { value: 'png', label: 'PNG', tag: 'Lossless' },
    { value: 'jpg', label: 'JPG', tag: 'Smallest' },
    { value: 'webp', label: 'WebP', tag: 'Modern' },
  ];
</script>

<template>
  <GlideSelect
    v-model="format"
    :options="formats"
    aria-label="Export format"
    @change="(value, option) => console.log(value, option.tag)"
  />
</template>
```

The highlight is a single absolutely positioned pill, moved with a CSS `transform` transition. When the menu opens, or when the pointer enters from outside, the pill jumps instead of gliding, so it never slides in from row 0.

## Props

<table>
<thead>
  <tr>
    <th>
      Prop
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Default
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        options
      </code>
    </td>
    
    <td>
      <code>
        (string | { value: string; label: string; tag?: string })[]
      </code>
    </td>
    
    <td>
      <code>
        ['One', 'Two', 'Three']
      </code>
    </td>
    
    <td>
      The options. A string is both value and label. <code>
        tag
      </code>
      
       shows on the right.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        model-value
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        undefined
      </code>
    </td>
    
    <td>
      Controlled value (<code>
        v-model
      </code>
      
      ).
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        default-value
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        ''
      </code>
    </td>
    
    <td>
      Initial value when uncontrolled.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        placeholder
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        'Select…'
      </code>
    </td>
    
    <td>
      Chip text when nothing is selected.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        show-tags
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      Show each option's tag.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        accent-color
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        '#f5f5f5'
      </code>
    </td>
    
    <td>
      Check mark and focus ring.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        surface-color
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        '#27272a'
      </code>
    </td>
    
    <td>
      Chip and menu background.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        highlight-color
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        '#3f3f46'
      </code>
    </td>
    
    <td>
      The gliding pill.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        text-color
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        '#f5f5f5'
      </code>
    </td>
    
    <td>
      Labels; tags and chevron use it at 55%.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        size
      </code>
    </td>
    
    <td>
      <code>
        'sm' | 'md' | 'lg'
      </code>
    </td>
    
    <td>
      <code>
        'md'
      </code>
    </td>
    
    <td>
      Chip height 28, 32 or 44 px; rows and font follow.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        radius
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        10
      </code>
    </td>
    
    <td>
      Menu corner radius in px. Chip and rows use radius minus 4.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        menu-width
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        176
      </code>
    </td>
    
    <td>
      Menu width in px. Never narrower than the chip.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        placement
      </code>
    </td>
    
    <td>
      <code>
        'top' | 'bottom'
      </code>
    </td>
    
    <td>
      <code>
        'bottom'
      </code>
    </td>
    
    <td>
      Preferred side. Flips if the menu does not fit in the viewport.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        align
      </code>
    </td>
    
    <td>
      <code>
        'left' | 'right'
      </code>
    </td>
    
    <td>
      <code>
        'left'
      </code>
    </td>
    
    <td>
      Edge the menu aligns to and pops from.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        pop-duration
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        180
      </code>
    </td>
    
    <td>
      Menu pop-in in ms. Pop-out takes two thirds of it.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        glide-duration
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        220
      </code>
    </td>
    
    <td>
      Pill glide between rows in ms.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        remember-position
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      The pill stays on the row the pointer left. Off, it clears on leave.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        disabled
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        false
      </code>
    </td>
    
    <td>
      Dims the chip and ignores input.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        aria-label
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        'Select'
      </code>
    </td>
    
    <td>
      Accessible name of the chip and the list.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        class
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        ''
      </code>
    </td>
    
    <td>
      Extra classes for the root.
    </td>
  </tr>
</tbody>
</table>

## Events

<table>
<thead>
  <tr>
    <th>
      Event
    </th>
    
    <th>
      Payload
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        update:modelValue
      </code>
    </td>
    
    <td>
      <code>
        (value: string)
      </code>
    </td>
    
    <td>
      A different option was picked.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        change
      </code>
    </td>
    
    <td>
      <code>
        (value: string, option: GlideSelectOption)
      </code>
    </td>
    
    <td>
      Same moment, with the option object.
    </td>
  </tr>
</tbody>
</table>

## Accessibility

- The chip is a `combobox` with `aria-expanded`, `aria-controls` and `aria-activedescendant`; the menu is a `listbox` of `option` rows with `aria-selected`.
- Enter, Space or the arrow keys open the menu. Arrow keys and Home / End move the highlight, letters jump by type-ahead, Enter or Space picks, Escape and Tab close.
- Focus stays on the chip the whole time. It shows a ring when focused from the keyboard.
- With `prefers-reduced-motion: reduce`, the menu fades without scaling and the pill moves without gliding.
- Ported from [React Bits](https://reactbits.dev/micro/glide-select) by David Haz.
