Menu

The agnostic-astro package utilizes XElement under-the-hood in order to provide build-time Astro components. These build-time components will help your project get closer to realizing a mostly no client-side runtime…if you do it right, this should mean an all-green 100% Lighthouse performance score! Leverage the benefits of Islands architecture by sending mostly server built agnostic-astro components. Then, sprinkle client-hydrated ones only as needed.

Usage

Ensure you've installed and setup the AgnosticUI Astro integration which will import the required common.min.css onto your page:

npm i astro-agnosticui

Then add the integration to your astro.config.mjs (you may need to run Astro with experimental integrations flag astro dev --experimental-integrations):

import { defineConfig } from 'astro/config';
import agnosticAstro from 'astro-agnosticui';;
export default defineConfig({
  integrations: [agnosticAstro()]
});

Then you can import Astro Menu component (agnostic-astro ships with the astro-agnosticui integration):

import AgMenu from 'agnostic-astro/Menu.astro';

The agnostic-astro package utilizes utilizes XElement. The agnostic-astro Menu supports inclusive navigation with a mouse or keyboard using the semantics described in the following table:

Menu Keyboard Navigation
Key Location Action
Enter, Space or On menu trigger button Opens menu options
On a menu item Moves focus to next item. If last item moves focus to first
On a menu item Moves focus to previous item. If first item moves focus to last
Enter or Space On a menu item Selects the menu items. If closeOnSelect will close the menu items
Home or End On a menu item Selects first or last menu item respectively
Esc On a menu item Closes menu items and places focus back on the menu trigger button
<AgMenu
  id="simple"
  buttonLabel="Tennis Players"
>
  <AgMenuItem>Andre Agassi</AgMenuItem>
  <AgMenuItem>Serena Williams</AgMenuItem>
  <AgMenuItem isDisabled>Rafael Nadal</AgMenuItem>
  <AgMenuItem>Roger Federer</AgMenuItem>
  <AgMenuItem>Althea Gibson</AgMenuItem>
  <AgMenuItem>Bjorn Borg</AgMenuItem>
</AgMenu>
<AgMenu
  id="simplesmall"
  buttonLabel="Tennis Players (small)"
  size="small"
>
  <AgMenuItem>Andre Agassi</AgMenuItem>
  <AgMenuItem>Serena Williams</AgMenuItem>
  <AgMenuItem isDisabled>Rafael Nadal</AgMenuItem>
  <AgMenuItem>Roger Federer</AgMenuItem>
  <AgMenuItem>Althea Gibson</AgMenuItem>
  <AgMenuItem>Bjorn Borg</AgMenuItem>
</AgMenu>
<AgMenu
  id="simple2"
  buttonLabel="Tennis Players (large)"
  size="large"
>
  <AgMenuItem>Andre Agassi</AgMenuItem>
  <AgMenuItem>Serena Williams</AgMenuItem>
  <AgMenuItem isDisabled>Rafael Nadal</AgMenuItem>
  <AgMenuItem>Roger Federer</AgMenuItem>
  <AgMenuItem>Althea Gibson</AgMenuItem>
  <AgMenuItem>Bjorn Borg</AgMenuItem>
</AgMenu>
<AgMenu
  id="kebabs"
  buttonLabel="Tennis Players (kebab)"
  type="kebab"
>
  <AgMenuItem>Andre Agassi</AgMenuItem>
  <AgMenuItem>Serena Williams</AgMenuItem>
  <AgMenuItem isDisabled>Rafael Nadal</AgMenuItem>
  <AgMenuItem>Roger Federer</AgMenuItem>
  <AgMenuItem>Althea Gibson</AgMenuItem>
  <AgMenuItem>Bjorn Borg</AgMenuItem>
</AgMenu>
<AgMenu
  id="hamburger"
  buttonLabel="Tennis Players (hamburger)"
  type="hamburger"
>
  <AgMenuItem>Andre Agassi</AgMenuItem>
  <AgMenuItem>Serena Williams</AgMenuItem>
  <AgMenuItem isDisabled>Rafael Nadal</AgMenuItem>
  <AgMenuItem>Roger Federer</AgMenuItem>
  <AgMenuItem>Althea Gibson</AgMenuItem>
  <AgMenuItem>Bjorn Borg</AgMenuItem>
</AgMenu>
<AgMenu
  id="meatball"
  buttonLabel="Tennis Players (meatball)"
  type="meatball"
>
  <AgMenuItem>Andre Agassi</AgMenuItem>
  <AgMenuItem>Serena Williams</AgMenuItem>
  <AgMenuItem isDisabled>Rafael Nadal</AgMenuItem>
  <AgMenuItem>Roger Federer</AgMenuItem>
  <AgMenuItem>Althea Gibson</AgMenuItem>
  <AgMenuItem>Bjorn Borg</AgMenuItem>
</AgMenu>

If you open the menu below, you will see we've preselected Roger Federer with isSelected and disabled some other players with isDisabled.

Also, we've wired up an onChange handler which logs to the console.

<AgMenu
  id="meatball-preselected"
  buttonLabel="Tennis Players meatball preselected"
  type="meatball"
  onChange={(itemEl, index) => console.log('Menu item: ', itemEl.textContent.trim(), ', index: ', index )}
>
  <AgMenuItem>Andre Agassi</AgMenuItem>
  <AgMenuItem>Serena Williams</AgMenuItem>
  <AgMenuItem>Rafael Nadal</AgMenuItem>
  <AgMenuItem isSelected>Roger Federer</AgMenuItem>
  <AgMenuItem isDisabled>Andy Roddick</AgMenuItem>
  <AgMenuItem>Anna Ivanovic</AgMenuItem>
  <AgMenuItem>Althea Gibson</AgMenuItem>
  <AgMenuItem isDisabled>Andy Murray</AgMenuItem>
  <AgMenuItem isDisabled>Martina Hingis</AgMenuItem>
  <AgMenuItem>Bjorn Borg</AgMenuItem>
</AgMenu>