Sub-Menus (Cascade)

Drill into nested option hierarchies with cascade sub-menus. Supports sync and async children loading.

File Tree Explorer

Click folders to expand sub-menus · Arrow keys to navigate

Pass a cascade config to enable drill-down sub-menus:

import { useVirtualSelect } from 'virtualized-ui';
import type { CascadeConfig } from 'virtualized-ui';

interface FileNode {
  id: string;
  name: string;
  type: 'folder' | 'file';
}

const cascade: CascadeConfig<FileNode> = {
  getChildren: (node) => {
    if (node.type === 'file') return null;
    return fetchChildren(node.id); // sync or async
  },
  hasChildren: (node) => node.type === 'folder',
};

const select = useVirtualSelect({
  options: rootItems,
  getOptionValue: (n) => n.id,
  getOptionLabel: (n) => n.name,
  cascade,
});

Open sub-menus programmatically:

// Open a sub-menu for a specific option
select.openSubMenu(folderNode);

// Close all open sub-menus
select.closeSubMenus();

// Access sub-menu state
select.subMenus; // SubMenuState[]

CascadeConfig

OptionTypeDescription
getChildren(option: T) => T[] | Promise<T[]> | nullReturn child options (null = no children)
hasChildren(option: T) => booleanOptional quick check to show expand indicator

Each open sub-menu exposes its state:

FieldTypeDescription
parentOptionTThe option that opened this sub-menu
parentValuestringThe parent’s value string
optionsT[]Child options in this sub-menu
depthnumberNesting depth (0-indexed)
isLoadingbooleanWhether async children are loading
focusedIndexnumberCurrently focused child index

Async Children

Return a Promise from getChildren to load children asynchronously. The sub-menu shows a loading state while the promise resolves:

const cascade: CascadeConfig<Category> = {
  getChildren: async (category) => {
    const res = await fetch(`/api/categories/${category.id}/children`);
    return res.json();
  },
  hasChildren: (category) => category.hasSubcategories,
};

Keyboard Navigation

KeyAction
ArrowRightOpen sub-menu for focused option
ArrowLeftClose deepest sub-menu
EscapeClose deepest sub-menu (or close menu if none)
EnterSelect focused option / open sub-menu for folders
Powered by grishaLR
© 2026 virtualized-ui. All rights reserved.