Skip to content

TicFrame v5.7.0-alpha.1 is available - read the changelog.

TicFrame

Components

Menu

TicFrame menus are semantic action and navigation lists with roving focus, selectable states, submenus, context menus, and responsive mega-menu behavior. They use only tf-* classes and framework-owned JavaScript.

Menus initialize automatically through TicFrame.init(). Use buttons for actions, links for navigation, and UID-only Ticons classes when an icon is decorative.

How It Works

Start with .tf-menu and .tf-menu-item. TicFrame applies role="menu", item roles, roving tabindex, orientation-aware arrow keys, disabled-item skipping, selected state, and framework events.

Keyboard model

Arrow keys move between enabled items. Home and End jump to the edges. Enter or Space activates checkable items and opens submenus.

Responsive model

Logical spacing, RTL-aware arrow direction, dark-mode tokens, scrollable panels, and mobile submenu stacking ship from TicFrame.

Core Menus

Use these variants for simple actions, toolbars, compact icon actions, and descriptive commands.

Basic, vertical, and horizontal menus

Vertical is the default. Add tf-menu-horizontal for toolbar-style menus.

HTML
<ul class="tf-menu" aria-label="Basic actions">
  <li><button type="button" class="tf-menu-item" aria-selected="true">Rename</button></li>
  <li><button type="button" class="tf-menu-item">Duplicate</button></li>
  <li><button type="button" class="tf-menu-item" aria-disabled="true">Archive</button></li>
</ul>

<ul class="tf-menu tf-menu-horizontal" aria-label="Horizontal actions">
  <li><button type="button" class="tf-menu-item" aria-selected="true">Overview</button></li>
  <li><button type="button" class="tf-menu-item">Activity</button></li>
  <li><button type="button" class="tf-menu-item">Settings</button></li>
</ul>

Icon menu, descriptions, and badges

Use item content helpers for rich labels that remain readable and screen-reader friendly.

HTML
<ul class="tf-menu" aria-label="Icon actions">
  <li><button type="button" class="tf-menu-item"><span class="tf-menu-item-icon"><i class="ti ti-029557" aria-hidden="true"></i></span><span>Open</span></button></li>
</ul>

<ul class="tf-menu" aria-label="Descriptive actions">
  <li><button type="button" class="tf-menu-item"><span class="tf-menu-item-content"><span class="tf-menu-item-title">Share project</span><span class="tf-menu-item-description">Send a private link to teammates.</span></span></button></li>
</ul>

<ul class="tf-menu" aria-label="Inbox views">
  <li><button type="button" class="tf-menu-item" aria-selected="true"><span>Assigned to me</span><span class="tf-menu-badge">12</span></button></li>
</ul>

Headings and dividers

Group related commands without making the headings keyboard stops.


HTML
<ul class="tf-menu" aria-label="Workspace actions">
  <li class="tf-menu-heading" aria-hidden="true">Project</li>
  <li><button type="button" class="tf-menu-item">Edit details</button></li>
  <li><button type="button" class="tf-menu-item">Invite members</button></li>
  <li><hr class="tf-menu-divider"></li>
  <li class="tf-menu-heading" aria-hidden="true">Danger zone</li>
  <li><button type="button" class="tf-menu-item" aria-disabled="true">Delete project</button></li>
</ul>

Selection Menus

Use aria-selected for single highlighted actions, and checkable menu item roles for persistent preferences.

Selectable, checkbox, and radio menus

TicFrame updates check and radio state, emits tf:menu:change, and keeps focus on the active item.

HTML
<ul class="tf-menu tf-menu-selectable" aria-label="View mode">
  <li><button type="button" class="tf-menu-item" aria-selected="true">List</button></li>
</ul>

<ul class="tf-menu" aria-label="Visible columns">
  <li><button type="button" class="tf-menu-item" role="menuitemcheckbox" aria-checked="true"><span><span class="tf-menu-check" aria-hidden="true">x</span> Name</span></button></li>
</ul>

<ul class="tf-menu" aria-label="Density">
  <li><button type="button" class="tf-menu-item" role="menuitemradio" data-tf-menu-group="density" aria-checked="true"><span><span class="tf-menu-radio" aria-hidden="true">o</span> Comfortable</span></button></li>
</ul>

Mega Menus

Mega menus use .tf-mega-menu, a trigger, and a .tf-mega-panel. Desktop click and hover modes, keyboard open, Escape close, outside-click close, focus restoration, RTL-safe positioning, and mobile accordion-style stacking are framework behavior.

Mega menu, multi-column mega menu, and full-width mega menu

Use data-tf-mega-mode="click", hover, or both. Add tf-mega-full for full-width placement.

HTML
<div class="tf-mega-menu" data-tf-mega-mode="click">
  <button type="button" class="tf-btn" data-tf-mega-trigger>Products</button>
  <div class="tf-mega-panel">
    <div class="tf-mega-grid">
      <div class="tf-mega-column"><p class="tf-menu-heading">Framework</p><a class="tf-menu-item" href="/docs/quick-start">Quick start</a></div>
      <div class="tf-mega-column"><p class="tf-menu-heading">Build</p><a class="tf-menu-item" href="/utilities">Utilities</a></div>
    </div>
  </div>
</div>

<div class="tf-mega-menu tf-mega-full" data-tf-mega-mode="both">
  <button type="button" class="tf-btn" data-tf-mega-trigger>Full-width resources</button>
  <div class="tf-mega-panel">
    <div class="tf-mega-grid">
      <div class="tf-mega-column"><p class="tf-menu-heading">Docs</p><a class="tf-menu-item" href="/docs/quick-start">Quick start</a></div>
      <div class="tf-mega-column"><p class="tf-menu-heading">Examples</p><a class="tf-menu-item" href="/examples">Examples home</a></div>
      <div class="tf-mega-column"><p class="tf-menu-heading">Support</p><a class="tf-menu-item" href="/community">Community</a></div>
    </div>
  </div>
</div>

Mega menu with icons, descriptions, featured content, and calls to action

Feature panels, icons, rich descriptions, and CTAs stay inside the same accessible disclosure panel.

HTML
<div class="tf-mega-menu tf-mega-full" data-tf-mega-mode="both">
  <button type="button" class="tf-btn tf-btn-primary" data-tf-mega-trigger>Explore TicFrame</button>
  <div class="tf-mega-panel">
    <div class="tf-mega-grid">
      <div class="tf-mega-column">
        <p class="tf-menu-heading">Build faster</p>
        <a class="tf-menu-item" href="/components"><span class="tf-menu-item-icon"><i class="ti ti-029557" aria-hidden="true"></i></span><span class="tf-menu-item-content"><span class="tf-menu-item-title">Components</span><span class="tf-menu-item-description">Accessible UI primitives with framework JavaScript.</span></span></a>
      </div>
      <div class="tf-mega-feature">
        <p class="tf-badge">Featured</p>
        <h3 class="tf-text-xl tf-font-semibold">Production docs kit</h3>
        <p class="tf-text-muted">Ship documentation without custom CSS.</p>
        <div class="tf-mega-cta"><a class="tf-btn tf-btn-primary" href="/docs/quick-start">Start building</a><a class="tf-btn" href="/examples">View examples</a></div>
      </div>
    </div>
  </div>
</div>

Accessibility

RequirementTicFrame behavior or guidance
NameEvery menu needs an accessible name through visible context or aria-label.
RolesTicFrame adds role="menu" and role="menuitem" when omitted. Checkable items keep authored menuitemcheckbox or menuitemradio.
KeyboardArrow keys move focus. Home and End jump. Enter and Space activate checkable items and submenu triggers.
DismissalSubmenus, context menus, and mega menus close on Escape and outside click. Focus returns to the trigger when closed from the keyboard.
Disabled stateUse native disabled on buttons or aria-disabled="true" when the item cannot be disabled natively.
RTLHorizontal arrow movement and submenu arrows mirror automatically from document direction.

API Reference

Classes

ClassPurpose
tf-menu, tf-menu-itemRequired menu root and interactive item.
tf-menu-horizontal, tf-menu-vertical, tf-menu-compactOrientation and density variants.
tf-menu-item-content, tf-menu-item-title, tf-menu-item-description, tf-menu-item-iconRich item anatomy.
tf-menu-heading, tf-menu-divider, tf-menu-badgeGrouping and metadata helpers.
tf-submenu, tf-submenu-trigger, tf-submenu-panelNested and multi-level menu surfaces.
tf-context-menu, tf-command-menu, tf-menu-sidebar, tf-menu-drawer, tf-menu-tabs, tf-menu-scrollableSpecialized menu surfaces.
tf-mega-menu, tf-mega-trigger, tf-mega-panel, tf-mega-grid, tf-mega-column, tf-mega-feature, tf-mega-cta, tf-mega-fullMega-menu layout and content primitives.

Attributes

AttributeValuesDescription
data-tf-menu-orientationvertical, horizontalOverrides automatic orientation detection.
data-tf-menu-submenuSelector or controlled idConnects a menu item to its submenu panel.
data-tf-menu-groupStringGroups radio menu items so only one can be checked.
data-tf-context-menuMenu selectorAttaches a context menu to a target region.
data-tf-mega-menuPresenceMarks a custom mega-menu root when the class is not present.
data-tf-mega-triggerPresenceMarks the mega-menu disclosure trigger.
data-tf-mega-modeclick, hover, bothChooses desktop opening behavior. Keyboard support is always enabled.

Methods and events

Method or eventPurpose
TicFrame.Menu.open(target)Opens a hidden menu or panel and marks it data-state="open".
TicFrame.Menu.close(target)Hides a menu or panel and marks it data-state="closed".
TicFrame.Menu.toggle(target)Toggles hidden/open state.
TicFrame.Menu.highlight(menu, itemOrIndex)Moves roving focus to an item or enabled item index.
tf:menu:highlight, tf:menu:select, tf:menu:changeFire when focus, activation, or check state changes.
tf:context-menu:open, tf:context-menu:close, tf:mega-menu:open, tf:mega-menu:closeFire from the corresponding disclosure surfaces.
JavaScript
const menu = document.querySelector("#project-menu");
TicFrame.Menu.open(menu);
TicFrame.Menu.highlight(menu, 1);
TicFrame.Menu.close(menu);

Tokens and Troubleshooting

Token or issueResolution
--tf-menu-min-inline-sizeControls menu width. Override through a theme or component scope, not website CSS.
--tf-menu-max-block-sizeUsed by tf-menu-scrollable for tall menus.
--tf-menu-item-padding-*Controls menu item spacing and inherits density choices.
--tf-mega-panel-inline-sizeControls mega panel width.
Menu appears in the TOCKeep preview headings inside tf-doc-example or add data-tf-toc-ignore.
Submenu does not openConfirm the trigger has data-tf-menu-submenu and the target panel id exists.
Screen reader does not announce a menu purposeAdd aria-label or wrap the menu in a labelled navigation landmark.