Files
basecoat/docs/components/select.njk
T
2025-04-29 19:14:31 +08:00

181 lines
6.8 KiB
Plaintext

---
layout: layouts/component.njk
title: Select
description: Displays a list of options for the user to pick from—triggered by a button.
toc:
- label: Usage
id: usage
children:
- label: HTML
id: usage-html
- label: HTML + Javascript
id: usage-js
- label: Jinja or Nunjucks
id: usage-jinja
- label: Examples
id: examples
children:
- label: Scrollable
id: example-scrollable
- label: Disabled
id: example-disabled
- label: With icon
id: example-with-icon
---
{% from "macros/code_preview.njk" import code_preview %}
{% from "macros/code_block.njk" import code_block %}
{% from "components/select.njk" import select %}
{% set code_native %}<select class="select w-[180px]">
<optgroup label="Fruits">
<option>Apple</option>
<option>Banana</option>
<option>Blueberry</option>
<option>Grapes</option>
<option>Pineapple</option>
</select>{% endset %}
{{ code_preview("select-native", code_native) }}
{% set code_html %}
{% call select(
name="select-js",
trigger_attrs={"class": "w-[180px]"},
register_on=["alpine:init", "htmx:afterSwap"]
) %}
<div role="group" aria-labelledby="fruit-options-label">
<span id="fruit-options-label" role="heading">Fruits</span>
<div role="option" data-value="apple">Apple</div>
<div role="option" data-value="banana">Banana</div>
<div role="option" data-value="blueberry">Blueberry</div>
<div role="option" data-value="pineapple">Grapes</div>
<div role="option" data-value="pineapple">Pineapple</div>
</div>
{% endcall %}
{% endset %}
{% set code_script %}
{% include "components/select-script.njk" %}
{% endset %}
{{ code_preview("combobox", code_script | prettyHtml ~ code_html | prettyHtml) }}
<h2 id="usage"><a href="#usage">Usage</a></h2>
<h3 id="usage-html"><a href="#usage-html">HTML</a></h3>
<section class="prose my-6">
<p>If you use a <code>&lt;select&gt;</code> element, just add the <code>select</code> class to it or have a parent with the <code>form</code> class (<a href="/components/form">read more about form</a>).</p>
</section>
{{ code_block(code_native) }}
<h3 id="usage-js"><a href="#usage-js">HTML + Javascript</a></h3>
<div class="alert my-6">
{% lucide "circle-alert" %}
<h2>This component requires Javascript.</h2>
<section>
<p>You will need to include the Javascript (Alpine.js) code provided below before the HTML code for this component. As with all interactive components, you will need to add some Alpine.js properties to certain elements (e.g. <code class="text-xs">x-bind</code>, <code class="text-xs">x-data</code>, <code class="text-xs">@click</code>).</p>
</section>
</div>
<section class="prose my-6">
<p>If you need to do more than what <code>&lt;select&gt;</code> allows (e.g. HTML options), you can use this component. It is structured as such:</p>
<ul>
<li>A <code>&lt;div class="popover"&gt;</code> which wraps around the entire component and holds it state (e.g. open/close).</li>
<li>A <code>&lt;button&gt;</code> that acts as the trigger to open or close the popover.</li>
<li>A <code>&lt;div data-popover&gt;</code> that holds the content of the popover.</li>
<li>Inside of the <code>&lt;div data-popover&gt;</code> is a <code>&lt;nav role="listbox"&gt;</code> that contains a combination of:
<ul>
<li><code>&lt;div role="option"&gt;</code> for the options with a <code>data-value</code> attribute.</li>
<li><code>&lt;hr role="separator"&gt;</code> to display a horizontal separator.</li>
<li><code>&lt;div role="group"&gt;</code> to group options.</li>
<li><code>&lt;span role="heading"&gt;</code> for group headings.</li>
</ul>
</li>
<li>An <code>&lt;input type="hidden"&gt;</code> to hold the value of the field (if needed).</li>
</ul>
<p>As with the <a href="/components/popover">Popover</a> component, you can set up a few additional options on the <code>&lt;div data-popover&gt;</code> element:</p>
<ul>
<li><code>data-side</code> can be set to <code>top</code>, <code>bottom</code>, <code>left</code>, or <code>right</code> to change the side of the popover.</li>
<li><code>data-align</code> can be set to <code>start</code>, <code>center</code>, or <code>end</code> to change the alignment of the popover.</li>
</ul>
</section>
{% from "components/tabs.njk" import tabs %}
{% set tabsets = [
{ tab: "HTML", panel: code_block(code_html | prettyHtml) },
{ tab: "Javascipt (Alpine.js)", panel: code_block(code_script | prettyHtml) }
] %}
{{ tabs(id="select", tabsets=tabsets) }}
<h3 id="usage-jinja"><a href="#usage-jinja">Jinja or Nunjucks</a></h3>
<p class="my-6 prose">If you use Jinja (or Nunjucks), you can use the <code>dropdown_menu()</code> macro directly. <a href="/installation#jinja-and-nunjucks">Read more about using Basecoat with Jinja and Nunjucks</a>.</p>
{% set raw_code %}{% raw %}{% call select(name="select-js") %}
<div role="group" aria-labelledby="fruit-options-label">
<span id="fruit-options-label" role="heading">Fruits</span>
<div role="option" data-value="apple">Apple</div>
<div role="option" data-value="banana">Banana</div>
<div role="option" data-value="blueberry">Blueberry</div>
<div role="option" data-value="pineapple">Grapes</div>
<div role="option" data-value="pineapple">Pineapple</div>
</div>
{% endcall %}{% endraw %}{% endset %}
{{ code_block(raw_code, "jinja") }}
<h2 id="examples"><a href="#examples">Examples</a></h2>
<h3 id="example-scrollable"><a href="#example-scrollable">Scrollable</a></h3>
{% set code %}
{% call select(
listbox_attrs={"class": "scrollbar overflow-y-auto max-h-64"},
register_on=["alpine:init", "htmx:afterSwap"]
) %}
{% for i in range(0, 99) %}
<div role="option" data-value="item-{{ i }}">Item {{ i }}</div>
{% endfor %}
{% endcall %}
{% endset %}
{{ code_preview("select-scrollable", code | prettyHtml) }}
<h3 id="example-disabled"><a href="#example-disabled">Disabled</a></h3>
{% set code %}
{% call select(
trigger_attrs={"disabled": "disabled"},
register_on=["alpine:init", "htmx:afterSwap"]
) %}
<div role="option" data-value="disabled">Disabled</div>
{% endcall %}
{% endset %}
{{ code_preview("select-disabled", code | prettyHtml) }}
<h3 id="example-with-icon"><a href="#example-with-icon">With icon</a></h3>
{% set code %}
{% call select(
trigger_attrs={'class': 'w-[180px]'},
register_on=["alpine:init", "htmx:afterSwap"]
) %}
<div type="button" role="option" data-value="bar">
{% lucide "chart-bar", {"class": "text-muted-foreground"} %}
Bar
</div>
<div type="button" role="option" data-value="line">
{% lucide "chart-line", {"class": "text-muted-foreground"} %}
Line
</div>
<div type="button" role="option" data-value="pie">
{% lucide "chart-pie", {"class": "text-muted-foreground"} %}
Pie
</div>
{% endcall %}
{% endset %}
{{ code_preview("select-scrollable", code | prettyHtml) }}