Fylgja Action List

An action list is a vertical stack of actions or links, such as the options for a file, a settings sidebar, or the contents of a dropdown. It is a plain list of native <button> and <a> elements styled as full width buttons, so every row is focusable, clickable across its whole width, and announced with its real role, without any extra ARIA.

Preview


<div style="--size-x: min(100%, 18rem); --btn-stroke: transparent">
	<ul role="list">
		<li>
			<button type="button" class="w-full align" style="--align: center start">
				<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg>
				<span>Copy link</span>
			</button>
		</li>
		<li>
			<button type="button" class="w-full align" style="--align: center start">
				<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"/></svg>
				<span>Rename</span>
			</button>
		</li>
		<li>
			<button type="button" class="w-full align" style="--align: center start">
				<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><path d="m7 10 5 5 5-5"/><path d="M12 15V3"/></svg>
				<span>Download</span>
			</button>
		</li>
	</ul>
	<hr style="--my: 0.25rem; border-block-end-width: 1px; border-color: color-mix(in oklab, var(--root-bg) 75%, var(--root-fg))">
	<ul role="list">
		<li>
			<button type="button" class="w-full align" style="--align: center start; --btn-color: color-mix(in oklab, oklch(58% 0.21 var(--hue-red)) 80%, var(--root-fg))">
				<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 6h18"/><path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6"/><path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"/></svg>
				<span>Delete file</span>
			</button>
		</li>
	</ul>
</div>

Usage

  • Put the rows in a <ul role="list">, one <li> per action.
  • Make each row a <button type="button"> for an action, or an <a class="btn"> for a link, with w-full align and --align: center start so the icon and label start at the left edge.
  • Set --btn-stroke: transparent once on the wrapper. It inherits down to every row, so the buttons lose their border but keep the hover and active backgrounds.
  • Separate groups of actions with an <hr> between two lists, and put destructive actions in their own group at the end.
  • Color a danger row by setting --hue to var(--hue-red) and pointing --btn-color at a tinted token, mixed with --root-fg so it stays readable in light and dark mode.

Anatomy

Part Responsibility
<ul role="list"> Groups the rows and announces how many there are.
<button> or <a class="btn"> One row. Full width, with the hover and active styles of a button.
Leading <svg> Optional icon, hidden from assistive technology.
<span class="flex-col"> Optional, stacks a label above a <small> description.
<hr> Optional divider between groups.

Accessibility

  • Native buttons and links are in the tab order and work with Enter (and Space for buttons) out of the box.
  • Mark icons aria-hidden="true"; the visible label names the row. An icon only row needs an aria-label.
  • In a navigation list, wrap it in a labeled <nav> and mark the current page aria-current="page". Fylgja’s button active style picks it up, so no extra class is needed.
  • A description inside the row is read as part of its name. Keep it short, or move it to aria-describedby if the label alone should be the name.

Variants

With descriptions

A label with a short description under it, here as a settings navigation. The rows are links, so the list sits in a labeled <nav>, and the current page is marked with aria-current="page".

<nav aria-label="Settings" style="--size-x: min(100%, 22rem); --btn-stroke: transparent">
	<ul>
		<li>
			<a href="#" class="btn w-full align" style="--align: center start" aria-current="page">
				<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="8" r="5"/><path d="M20 21a8 8 0 0 0-16 0"/></svg>
				<span class="flex-col">
					Profile
					<small class="font-normal" style="color: color-mix(in oklab, currentcolor 75%, transparent)">Name, photo, and bio</small>
				</span>
			</a>
		</li>
		<li>
			<a href="#" class="btn w-full align" style="--align: center start">
				<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9"/><path d="M10.3 21a1.94 1.94 0 0 0 3.4 0"/></svg>
				<span class="flex-col">
					Notifications
					<small class="font-normal" style="color: color-mix(in oklab, currentcolor 75%, transparent)">Email and push alerts</small>
				</span>
			</a>
		</li>
		<li>
			<a href="#" class="btn w-full align" style="--align: center start">
				<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect width="18" height="11" x="3" y="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>
				<span class="flex-col">
					Security
					<small class="font-normal" style="color: color-mix(in oklab, currentcolor 75%, transparent)">Password and passkeys</small>
				</span>
			</a>
		</li>
	</ul>
</nav>

Related: Menu, Navbar.

FAQ

Should I use buttons or links?

It depends on what the row does. A row that goes somewhere is an <a href>, a row that does something on the current page (copy, rename, delete) is a <button type="button">. Both get the same look from Fylgja's .btn styles, so you can mix them in one list.

Why role="list" on the lists?

Fylgja removes the bullets from a list with role="list", and the role keeps the list semantics that some browsers drop once the bullets are gone. Inside a <nav> the bullets are already removed and the list keeps its semantics, so the navigation version needs no role.

Why two lists and an <hr> instead of one list with a divider item?

A <ul> may only contain <li> elements, so the divider cannot sit between items. Splitting the actions into groups keeps the markup valid, and the <hr> is announced as a separator, which is exactly what it is.

Can I use it inside a dropdown?

Yes. The Menu turns the same items into a popover <menu>.