Skip to content

andyed/fisheye-menu

Repository files navigation

Fisheye Flyout Menu

Fisheye Flyout Menu logo

Fisheye Flyout Menu demo showing Dewey Decimal taxonomy with 600 Technology expanded

Luxuriously usable cascading menus. Items dynamically resize based on mouse proximity, applying Fitts's Law to reduce target acquisition time in deep menu hierarchies. Travel to the flyout menu is enabled with a free zone computed with trigonometry. Mouse targets are carefully preserved even as the menu animates. Full keyboard navigation with ARIA roles for screen reader accessibility.

Live Demo

Fitts's Law Primer

Paul Fitts showed in 1954 that the time to move to a target depends on two things: how far away it is (D) and how big it is (W).

Fitts's Law: standard menu vs fisheye menu

The formula:

MT = a + b · log₂(2D / W)

In a standard menu, every item has the same height (W). The item at the bottom of a long list has high D and unchanged W — slow to reach. A fisheye menu increases W for the item you're approaching, reducing acquisition time without changing the menu's total footprint.

The effect compounds across cascading menus. Each submenu level adds distance. Fisheye sizing at every level means the cumulative penalty stays manageable instead of growing exponentially with depth.

The Tunneling Problem

Cascading menus have a second failure mode: the diagonal path. When you move from a parent item toward a flyout submenu, your mouse crosses other parent items along the way — which close the flyout you were heading toward. Users learn to move right first, then down, adding a dogleg that doubles the motor cost.

Steering corridor: the diagonal problem and the solution

This implementation defines a free travel zone — a triangle from the cursor to the lower-left corner of the open flyout. Any mouse path inside this zone is heading toward the flyout, so item-switch events are suppressed. Combined with a movement direction check (horizontal movement > vertical = steering; vertical dominates = switching items), the flyout stays open during diagonal travel but closes immediately when the user moves down to select a different parent item.

This is a well-known technique in HCI, predating Amazon's 2013 patent (now expired) on a specific mega-menu implementation. The geometric insight — protect the user's diagonal path to a submenu — follows directly from Fitts's and Accot-Zhai's steering law research and was taught in human factors curricula by the early 1990s.

Background

This approach was originally prototyped as a "fisheye menu" during Andy Edmonds' MS research in Human Factors at Clemson University, exploring mouse-position-dependent target sizing in hierarchical menus (2005 prototype screenshot). The core insight: if you make the item the user is heading toward taller, and ensure the boundaries they'd cross don't shift against them, you get faster traversal without sacrificing menu density.

Configuration

All behavior is controlled via the CONFIG object in fisheye-menu.js:

Parameter Default Description
baseHeight 28 Default item height in pixels
maxExpand 2.4 Maximum expansion factor for hovered item
minHeight 21 Minimum compressed height (readability floor)
falloffRadius 4 Number of neighbors that get partial expansion
transitionMs 80 CSS transition duration
separator 'line' Item separator style: false, 'line', or 'groove'
separatorColor 'rgba(255,255,255,0.08)' Separator color
separatorThickness 1 Separator thickness in pixels

Demo Taxonomies

The demo includes several real-world hierarchies for testing at various depths and item counts:

  • Biology — Linnaean taxonomy (Kingdom → Order), 4 levels deep
  • Chemistry — Periodic table element groups
  • Typography — Typeface classification (Vox-ATypI style)
  • Dewey Decimal — Library classification system
  • Palettes — Color themes from Psychodeli+ with visual swatches

Usage

No build step. ES6 modules — import and call create():

<div id="my-menu"></div>

<script type="module">
import { create } from './fisheye-menu.js';

const menu = create(document.getElementById('my-menu'), [
  { label: 'File', children: [
    { label: 'New' },
    { label: 'Open' },
    { label: 'Recent', children: [
      { label: 'document.txt' },
      { label: 'notes.md' },
    ]},
    { label: 'Save' },
  ]},
  { label: 'Edit', children: [
    { label: 'Undo' },
    { label: 'Redo' },
    { label: 'Find' },
  ]},
], {
  onSelect: (item) => console.log('Selected:', item.label),
});

// Later: menu.destroy() to clean up
</script>

Data format

Each menu item is an object with:

  • label — display text (required)
  • children — array of child items (makes it a submenu trigger)
  • swatch[r, g, b] array to show a color dot (optional)

Use the string '---' for a separator.

Options

All options are optional. See the Configuration table for layout parameters. Additional options:

Option Default Description
onSelect null (item) => {} — called when a leaf item is clicked or Enter'd
overlay false Dim the background when a menu is open
theme 'dark' 'dark', 'light', or null to inherit your own CSS custom properties
debug false Show live height values in an overlay

Cleanup

create() returns an object with a destroy() method that removes all DOM elements and event listeners.

Styles

Include fisheye-menu.css for the default dark theme:

<link rel="stylesheet" href="fisheye-menu.css">

The stylesheet uses CSS custom properties (--fisheye-*) for all colors. Override any variable on an ancestor element for custom theming, or pass theme: null and define your own values. All layout is handled by JS — the stylesheet controls appearance only. Menu panels are appended to document.body for correct positioning.

References

  • Fitts, P. M. (1954). The information capacity of the human motor system in controlling the amplitude of movement. Journal of Experimental Psychology, 47(6), 381–391.

  • Bederson, B. B. (2000). Fisheye menus. Proceedings of UIST 2000, 217–225. The original fisheye menu concept — magnifying items near the cursor in linear lists.

  • Ahlström, D., Alexandrowicz, R., & Hitz, M. (2005). Modeling and improving selection in cascading pull-down menus using Fitts' law, the steering law and force fields. Proceedings of CHI 2005. Fitts's law analysis of cascading menu traversal.

  • Cockburn, A., & Gutwin, C. (2007). Untangling the usability of fisheye menus. ACM Transactions on Computer-Human Interaction, 14(2). Found Dock-style fisheye menus slower than traditional menus — but tested a variant where magnification distorts spatial layout. Our approach differs: total menu height is fixed, only proportions shift, preserving spatial memory.

  • Tanvir, E., Cullen, J., Irani, P., & Cockburn, A. (2011). Improving cascading menu selections with adaptive activation areas. International Journal of Human-Computer Studies, 69(12), 769–785. Triangular activation areas for diagonal submenu access — the steering corridor technique.

  • Accot, J., & Zhai, S. (1997). Beyond Fitts' law: Models for trajectory-based HCI tasks. Proceedings of CHI 1997, 295–302. The steering law: movement time through a tunnel is proportional to tunnel length/width. Foundational for understanding cascading menu traversal costs.

License

MIT

About

Luxuriously usable cascading menus with Fitts's Law optimization

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors