mirror of
https://github.com/hunvreus/basecoat.git
synced 2026-11-12 13:18:22 +00:00
389 lines
14 KiB
Plaintext
389 lines
14 KiB
Plaintext
---
|
|
layout: layouts/page.njk
|
|
title: Dropdown Menu
|
|
description: Displays a menu to the user — such as a set of actions or functions — triggered by a button.
|
|
toc:
|
|
- label: Usage
|
|
id: usage
|
|
children:
|
|
- label: HTML + JavaScript
|
|
id: usage-html-js
|
|
children:
|
|
- label: "Step 1: Include the JavaScript files"
|
|
id: usage-html-js-1
|
|
- label: "Step 2: Add your dropdown menu HTML"
|
|
id: usage-html-js-2
|
|
- label: HTML structure
|
|
id: usage-html-js-3
|
|
- label: Jinja and Nunjucks
|
|
id: usage-macro
|
|
- label: Examples
|
|
id: examples
|
|
children:
|
|
- label: Checkboxes
|
|
id: example-checkboxes
|
|
- label: Radio Group
|
|
id: example-radio-group
|
|
---
|
|
|
|
{% from "macros/code_block.njk" import code_block %}
|
|
{% from "macros/code_preview.njk" import code_preview %}
|
|
{% from "dropdown-menu.njk" import dropdown_menu %}
|
|
|
|
{% set code_html %}
|
|
{% call dropdown_menu(
|
|
id="demo-dropdown-menu",
|
|
trigger="Open",
|
|
trigger_attrs={"class": "btn-outline"},
|
|
popover_attrs={"class": "min-w-56"}
|
|
) %}
|
|
<div role="group" aria-labelledby="account-options">
|
|
<span id="account-options" role="heading">My Account</span>
|
|
<button type="button" role="menuitem">
|
|
Profile
|
|
<span class="text-muted-foreground ml-auto text-xs tracking-widest">⇧⌘P</span>
|
|
</button>
|
|
<button type="button" role="menuitem">
|
|
Billing
|
|
<span class="text-muted-foreground ml-auto text-xs tracking-widest">⌘B</span>
|
|
</button>
|
|
<button type="button" role="menuitem">
|
|
Settings
|
|
<span class="text-muted-foreground ml-auto text-xs tracking-widest">⌘S</span>
|
|
</button>
|
|
<button type="button" role="menuitem">
|
|
Keyboard shortcuts
|
|
<span class="text-muted-foreground ml-auto text-xs tracking-widest">⌘K</span>
|
|
</button>
|
|
</div>
|
|
<hr role="separator">
|
|
<button type="button" role="menuitem">
|
|
GitHub
|
|
</button>
|
|
<button type="button" role="menuitem">
|
|
Support
|
|
</button>
|
|
<button type="button" role="menuitem" disabled>
|
|
API
|
|
</button>
|
|
<hr role="separator">
|
|
<button type="button" role="menuitem">
|
|
Logout
|
|
<span class="text-muted-foreground ml-auto text-xs tracking-widest">⇧⌘P</span>
|
|
</button>
|
|
{% endcall %}
|
|
{% endset %}
|
|
|
|
{{ code_preview("dropdown-menu", code_html | prettyHtml) }}
|
|
|
|
<h2 id="usage">Usage</h2>
|
|
|
|
<h3 id="usage-html-js"><a href="#usage-html-js">HTML + JavaScript</a></h3>
|
|
|
|
<h4 id="usage-html-js-1"><a href="#usage-html-js-1">Step 1: Include the JavaScript files</a></h4>
|
|
|
|
<section class="prose">
|
|
<p>Include the <a href="https://github.com/hunvreus/basecoat/blob/main/src/js/dropdown-menu.js" target="_blank"><code>dropdown-menu.js</code></a> file. It is recommended to also include the <a href="https://github.com/oddbird/css-anchor-positioning" target="_blank">CSS anchor positioning polyfill</a> to support older browsers. Add this to the <code><head></code> of your page:</p>
|
|
</section>
|
|
|
|
{% set code_script %}<script src="https://cdn.jsdelivr.net/npm/basecoat-css@{{ site.version }}/dist/js/dropdown-menu.min.js" defer></script>
|
|
<script type="module">
|
|
if (!("anchorName" in document.documentElement.style)) {
|
|
import("https://cdn.jsdelivr.net/npm/basecoat-css@{{ site.version }}/dist/js/css-anchor-positioning.min.js");
|
|
}
|
|
</script>{% endset %}
|
|
{{ code_block(code_script | prettyHtml, "html") }}
|
|
|
|
<div class="flex flex-wrap gap-2 my-6">
|
|
<a class="badge-outline" href="/installation/#install-js">
|
|
Components with JavaScript
|
|
{% lucide "arrow-right" %}
|
|
</a>
|
|
<a class="badge-outline" href="/installation/#install-cli">
|
|
Use the CLI
|
|
{% lucide "arrow-right" %}
|
|
</a>
|
|
<a class="badge-outline" href="https://github.com/hunvreus/basecoat/blob/main/src/js/dropdown-menu.js" target="_blank">
|
|
dropdown-menu.js
|
|
{% lucide "arrow-right" %}
|
|
</a>
|
|
</div>
|
|
|
|
<h4 id="usage-html-js-2"><a href="#usage-html-js-2">Step 2: Add your dropdown menu HTML</a></h4>
|
|
|
|
{{ code_block(code_html | prettyHtml, "html") }}
|
|
|
|
<h4 id="usage-html-js-3"><a href="#usage-html-js-3">HTML structure</a></h4>
|
|
|
|
<section class="prose">
|
|
<dl>
|
|
<dt><code class="highlight language-html"><div class="dropdown-menu"></code></dt>
|
|
<dd>Wraps around the entire component.
|
|
<dl>
|
|
<dt><code class="highlight language-html"><button type="button" popovertarget="{ POPOVER_ID }"></code></dt>
|
|
<dd>
|
|
<p>The trigger to open the popover, can also have the following attributes:</p>
|
|
<ul>
|
|
<li><code>id="{BUTTON_ID}"</code>: linked to by the <code>aria-labelledby</code> attribute of the listbox.</li>
|
|
<li><code>aria-haspopup="menu"</code>: indicates that the button opens a menu.</li>
|
|
<li><code>aria-controls="{ MENU_ID }"</code>: points to the menu's id.</li>
|
|
<li><code>aria-expanded="false"</code>: tracks the popover's state.</li>
|
|
</ul>
|
|
</dd>
|
|
<dt><code class="highlight language-html"><div popover class="popover" id="{ POPOVER_ID }"></code></dt>
|
|
<dd>As with the <a href="/components/popover">Popover</a> component, you can set up the side and alignment of the popover using the <code>data-side</code> and <code>data-align</code> attributes.
|
|
<dl>
|
|
<dt><code class="highlight language-html"><div role="menu"></code></dt>
|
|
<dd>The menu containing the options. Should have the following attributes:
|
|
<ul>
|
|
<li><code>id="{ MENU_ID }"</code>: refered to by the <code>aria-controls</code> attribute of the trigger.</li>
|
|
<li><code>aria-labelledby="{ BUTTON_ID }"</code>: linked to by the button's <code>id</code> attribute.</li>
|
|
</ul>
|
|
<dl>
|
|
<dt><code class="highlight language-html"><button role="menuitem"></code></dt>
|
|
<dd>Menu item.</dd>
|
|
<dt><code class="highlight language-html"><button role="menuitemcheckbox"></code></dt>
|
|
<dd>Menu item with a checkbox.</dd>
|
|
<dt><code class="highlight language-html"><button role="menuitemradio"></code></dt>
|
|
<dd>Menu item with a radio button.</dd>
|
|
<dt><code class="highlight language-html"><hr role="separator"></code> <span class="badge-secondary">Optional</span></dt>
|
|
<dd>Separator between groups/options.</dd>
|
|
<dt><code class="highlight language-html"><div role="group"></code> <span class="badge-secondary">Optional</span></dt>
|
|
<dd>Group of options, can have a <code>aria-labelledby</code> attribute to link to a heading.</dd>
|
|
<dt><code class="highlight language-html"><span role="heading"></code></dt>
|
|
<dd>Group heading, must have an <code>id</code> attribute if you use the <code>aria-labelledby</code> attribute on the group.</dd>
|
|
</dl>
|
|
</dd>
|
|
</dl>
|
|
</dl>
|
|
</dd>
|
|
</dl>
|
|
</section>
|
|
|
|
<h3 id="usage-macro"><a href="#usage-macro">Jinja and Nunjucks</a></h3>
|
|
|
|
<div class="prose">
|
|
<p>You can use the <code class="relative rounded bg-muted px-[0.3rem] py-[0.2rem] font-mono text-xs">dropdown_menu()</code> Nunjucks or Jinja macro for this component.</p>
|
|
</div>
|
|
|
|
<div class="flex flex-wrap gap-2 my-6">
|
|
<a class="badge-outline" href="/installation/#install-macros" target="_blank">
|
|
Use Nunjucks or Jinja macros
|
|
{% lucide "arrow-right" %}
|
|
</a>
|
|
<a class="badge-outline" href="https://github.com/hunvreus/basecoat/blob/main/src/jinja/dropdown-menu.html.jinja" target="_blank">
|
|
Jinja macro
|
|
{% lucide "arrow-right" %}
|
|
</a>
|
|
<a class="badge-outline" href="https://github.com/hunvreus/basecoat/blob/main/src/nunjucks/dropdown-menu.njk" target="_blank">
|
|
Nunjucks macro
|
|
{% lucide "arrow-right" %}
|
|
</a>
|
|
</div>
|
|
|
|
{% set raw_code %}{% raw %}{% call dropdown_menu(
|
|
id="dropdown-menu",
|
|
trigger="Open",
|
|
trigger_attrs={"class": "btn-outline"},
|
|
content_attrs={"class": "min-w-56"},
|
|
register_on=["alpine:init", "htmx:afterSwap"]
|
|
) %}
|
|
<div role="group" aria-labelledby="account-options">
|
|
<span id="account-options" role="heading">My Account</span>
|
|
<button type="button" role="menuitem">
|
|
Profile
|
|
<span class="text-muted-foreground ml-auto text-xs tracking-widest">⇧⌘P</span>
|
|
</button>
|
|
<button type="button" role="menuitem">
|
|
Billing
|
|
<span class="text-muted-foreground ml-auto text-xs tracking-widest">⌘B</span>
|
|
</button>
|
|
<button type="button" role="menuitem">
|
|
Settings
|
|
<span class="text-muted-foreground ml-auto text-xs tracking-widest">⌘S</span>
|
|
</button>
|
|
<button type="button" role="menuitem">
|
|
Keyboard shortcuts
|
|
<span class="text-muted-foreground ml-auto text-xs tracking-widest">⌘K</span>
|
|
</button>
|
|
</div>
|
|
<hr role="separator">
|
|
<button type="button" role="menuitem">
|
|
GitHub
|
|
</button>
|
|
<button type="button" role="menuitem">
|
|
Support
|
|
</button>
|
|
<button type="button" role="menuitem" disabled>
|
|
API
|
|
</button>
|
|
<hr role="separator">
|
|
<button type="button" role="menuitem">
|
|
Logout
|
|
<span class="text-muted-foreground ml-auto text-xs tracking-widest">⇧⌘P</span>
|
|
</button>
|
|
{% endcall %}{% endraw %}{% endset%}
|
|
{{ code_block(raw_code, "jinja") }}
|
|
|
|
<h2 id="examples"><a href="#examples">Examples</a></h2>
|
|
|
|
<h3 id="example-checkboxes"><a href="#example-checkboxes">Checkboxes</a></h3>
|
|
|
|
{% set code %}{% call dropdown_menu(
|
|
id="dropdown-menu-checkboxes",
|
|
trigger="Open",
|
|
trigger_attrs={"class": "btn-outline"},
|
|
content_attrs={"class": "min-w-56"},
|
|
register_on=["alpine:init", "htmx:afterSwap"]
|
|
) %}
|
|
<div role="group" aria-labelledby="account-options">
|
|
<span id="account-options" role="heading">Account Options</span>
|
|
<button type="button" role="menuitem">
|
|
{% lucide "user" %}
|
|
Profile
|
|
<span class="text-muted-foreground ml-auto text-xs tracking-widest">⇧⌘P</span>
|
|
</button>
|
|
<button type="button" role="menuitem">
|
|
{% lucide "credit-card" %}
|
|
Billing
|
|
<span class="text-muted-foreground ml-auto text-xs tracking-widest">⌘B</span>
|
|
</button>
|
|
<button type="button" role="menuitem">
|
|
{% lucide "settings" %}
|
|
Settings
|
|
<span class="text-muted-foreground ml-auto text-xs tracking-widest">⌘S</span>
|
|
</button>
|
|
</div>
|
|
<hr role="separator">
|
|
<div role="group" aria-labelledby="appearance-options">
|
|
<span id="appearance-options" role="heading">Appearance</span>
|
|
<button
|
|
type="button"
|
|
role="menuitemcheckbox"
|
|
aria-checked="true"
|
|
class="group"
|
|
x-data="{ checked: true }"
|
|
@click="checked = !checked"
|
|
:aria-checked="checked"
|
|
>
|
|
{% lucide "check", {
|
|
"class": "invisible group-aria-checked:visible",
|
|
"aria-hidden": "true",
|
|
"focusable": "false"
|
|
} %}
|
|
Status Bar
|
|
<span class="text-muted-foreground ml-auto text-xs tracking-widest">⇧⌘P</span>
|
|
</button>
|
|
<button
|
|
type="button"
|
|
role="menuitemcheckbox"
|
|
aria-checked="false"
|
|
class="group"
|
|
disabled
|
|
x-data="{ checked: false }"
|
|
@click="checked = !checked"
|
|
:aria-checked="checked"
|
|
>
|
|
{% lucide "check", {
|
|
"class": "invisible group-aria-checked:visible",
|
|
"aria-hidden": "true",
|
|
"focusable": "false"
|
|
} %}
|
|
Activity Bar
|
|
<span class="text-muted-foreground ml-auto text-xs tracking-widest">⌘B</span>
|
|
</button>
|
|
<button
|
|
type="button"
|
|
role="menuitemcheckbox"
|
|
aria-checked="false"
|
|
class="group"
|
|
x-data="{ checked: false }"
|
|
@click="checked = !checked"
|
|
:aria-checked="checked"
|
|
>
|
|
{% lucide "check", {
|
|
"class": "invisible group-aria-checked:visible",
|
|
"aria-hidden": "true",
|
|
"focusable": "false"
|
|
} %}
|
|
Panel
|
|
<span class="text-muted-foreground ml-auto text-xs tracking-widest">⌘S</span>
|
|
</button>
|
|
</div>
|
|
<hr role="separator">
|
|
<button type="button" role="menuitem">
|
|
{% lucide "log-out" %}
|
|
Logout
|
|
<span class="text-muted-foreground ml-auto text-xs tracking-widest">⇧⌘P</span>
|
|
</button>
|
|
{% endcall %}{% endset %}
|
|
{{ code_preview("dropdown-menu-checkboxes", code | prettyHtml) }}
|
|
|
|
<h3 id="example-radio-group"><a href="#example-radio-group">Radio Group</a></h3>
|
|
|
|
{% set code %}{% call dropdown_menu(
|
|
id="dropdown-menu-radio-group",
|
|
trigger="Open",
|
|
trigger_attrs={"class": "btn-outline"},
|
|
popover_attrs={"class": "min-w-56"}
|
|
) %}
|
|
<div role="group" aria-labelledby="position-options" x-data="{ checked: 'bottom' }">
|
|
<span id="position-options" role="heading">Panel Position</span>
|
|
<hr role="separator">
|
|
<button
|
|
type="button"
|
|
role="menuitemradio"
|
|
aria-checked="false"
|
|
class="group"
|
|
@click="checked = 'top'"
|
|
:aria-checked="checked == 'top'"
|
|
>
|
|
<div class="size-4 flex items-center justify-center">
|
|
<div
|
|
class="size-2 rounded-full bg-foreground invisible group-aria-checked:visible"
|
|
aria-hidden="true",
|
|
focusable="false"
|
|
></div>
|
|
</div>
|
|
Status Bar
|
|
<span class="text-muted-foreground ml-auto text-xs tracking-widest">⇧⌘P</span>
|
|
</button>
|
|
<button
|
|
type="button"
|
|
role="menuitemradio"
|
|
aria-checked="false"
|
|
class="group"
|
|
@click="checked = 'bottom'"
|
|
:aria-checked="checked == 'bottom'"
|
|
>
|
|
<div class="size-4 flex items-center justify-center">
|
|
<div
|
|
class="size-2 rounded-full bg-foreground invisible group-aria-checked:visible"
|
|
aria-hidden="true",
|
|
focusable="false"
|
|
></div>
|
|
</div>
|
|
Activity Bar
|
|
<span class="text-muted-foreground ml-auto text-xs tracking-widest">⌘B</span>
|
|
</button>
|
|
<button
|
|
type="button"
|
|
role="menuitemradio"
|
|
aria-checked="false"
|
|
class="group"
|
|
@click="checked = 'right'"
|
|
:aria-checked="checked == 'right'"
|
|
>
|
|
<div class="size-4 flex items-center justify-center">
|
|
<div
|
|
class="size-2 rounded-full bg-foreground invisible group-aria-checked:visible"
|
|
aria-hidden="true",
|
|
focusable="false"
|
|
></div>
|
|
</div>
|
|
Panel
|
|
<span class="text-muted-foreground ml-auto text-xs tracking-widest">⌘S</span>
|
|
</button>
|
|
</div>
|
|
{% endcall %}{% endset %}
|
|
{{ code_preview("dropdown-menu", code | prettyHtml) }} |