Skip to main content
You are viewing Pre-Alpha documentation.
Vuetify0 Logo
Theme
Mode
Palettes
Accessibility
Vuetify One

Sign in to Vuetify One

Access premium tools across the Vuetify ecosystem — Bin, Play, Studio, and more.

Not a subscriber? See what's included

useRovingFocus

A composable for keyboard navigation within composite widgets using the roving tabindex pattern.


IntermediateMar 18, 2026

Usage

useRovingFocus manages focus across a group of items — only the active item has tabindex="0", all others have tabindex="-1". Arrow keys move focus between items, automatically skipping disabled ones. Supports linear (horizontal/vertical) and grid (2D) navigation modes.

vue
<script setup lang="ts">
  import { useRovingFocus } from '@vuetify/v0'
  import { useTemplateRef } from 'vue'

  const toolbar = useTemplateRef('toolbar')

  const items = [
    { id: 'bold', label: 'Bold' },
    { id: 'italic', label: 'Italic' },
    { id: 'underline', label: 'Underline', disabled: true },
    { id: 'strike', label: 'Strikethrough' },
  ]

  const { focusedId, isTabbable } = useRovingFocus(
    () => items.map(item => ({
      id: item.id,
      el: () => toolbar.value?.querySelector(`[data-id="${item.id}"]`),
      disabled: item.disabled,
    })),
    { target: toolbar, orientation: 'horizontal' },
  )
</script>

<template>
  <div ref="toolbar" role="toolbar" aria-label="Formatting">
    <button
      v-for="item in items"
      :key="item.id"
      :data-id="item.id"
      :tabindex="isTabbable(item.id) ? 0 : -1"
      :disabled="item.disabled"
    >
      {{ item.label }}
    </button>
  </div>
</template>

Architecture

useRovingFocus builds on useEventListener for keydown handling. It is a standalone composable — not part of the registry/selection hierarchy — making it composable alongside createSingle or createSelection for widgets that separate focus from selection (e.g., listboxes, selects).

Roving Focus Architecture

Use controls to zoom and pan. Click outside or press Escape to close.

Roving Focus Architecture

Reactivity

Property/MethodReactiveNotes
focusedIdShallowRef, tracks currently focused item
isTabbable(id)-Returns true for the one item that should have tabindex="0"
focus(id)-Programmatically focus an item by ID
next()-Move focus to next enabled item
prev()-Move focus to previous enabled item
first()-Move focus to first enabled item
last()-Move focus to last enabled item
onKeydown-Keydown handler — auto-bound when target is provided

Examples

Color Grid

2D grid navigation with the columns option. Arrow keys navigate in two dimensions, Home/End are row-scoped, Ctrl+Home/End jump to absolute first/last.

FileRole
Grid.vueColor swatch grid with 2D keyboard navigation
grid.vueEntry point rendering a material color palette

API Reference

The following API details are for the useRovingFocus composable.

Functions

useRovingFocus

(items: () => RovingItem[], options?: RovingFocusOptions) => RovingFocusReturn

Options

target

MaybeRefOrGetter<HTMLElement | null | undefined>

orientation

"horizontal" | "vertical" | "both" | undefined

Arrow key mapping. Ignored when `columns` is set (grid uses all 4 arrows).

circular

boolean | undefined

columns

MaybeRefOrGetter<number> | undefined

Column count for grid navigation. When set, items are treated as a 2D grid in row-major order: Left/Right step ±1, Up/Down step ±columns, Home/End go to row start/end, Ctrl+Home/End go to first/last overall.

onFocus

((id: ID) => void) | undefined
Was this page helpful?

© 2016-1970 Vuetify, LLC
Ctrl+/