diff --git a/dist/basecoat.css b/dist/basecoat.css
index 77707a1..7873117 100644
--- a/dist/basecoat.css
+++ b/dist/basecoat.css
@@ -27,7 +27,6 @@
--color-black: #000;
--color-white: #fff;
--spacing: 0.25rem;
- --breakpoint-sm: 40rem;
--breakpoint-md: 48rem;
--breakpoint-lg: 64rem;
--container-xs: 20rem;
@@ -465,6 +464,9 @@
.w-6 {
width: calc(var(--spacing) * 6);
}
+ .w-48 {
+ width: calc(var(--spacing) * 48);
+ }
.w-72 {
width: calc(var(--spacing) * 72);
}
@@ -480,6 +482,9 @@
.w-\[180px\] {
width: 180px;
}
+ .w-\[200px\] {
+ width: 200px;
+ }
.w-\[var\(--sidebar-width\)\] {
width: var(--sidebar-width);
}
@@ -2827,12 +2832,6 @@
border-bottom-style: var(--tw-border-style);
border-bottom-width: 1px;
padding-inline: calc(var(--spacing) * 3);
- svg {
- width: calc(var(--spacing) * 4);
- height: calc(var(--spacing) * 4);
- flex-shrink: 0;
- opacity: 50%;
- }
input[role='combobox'] {
display: flex;
height: calc(var(--spacing) * 10);
diff --git a/dist/basecoat.tailwind.css b/dist/basecoat.tailwind.css
index 3d182a2..369c30a 100644
--- a/dist/basecoat.tailwind.css
+++ b/dist/basecoat.tailwind.css
@@ -652,19 +652,15 @@
[role='separator'] {
@apply border-border -mx-1 my-1;
}
+ /* Combobox */
> header {
@apply flex h-9 items-center gap-2 border-b px-3 -mx-1 -mt-1 mb-1;
- svg {
- @apply size-4 shrink-0 opacity-50;
- }
input[role='combobox'] {
@apply placeholder:text-muted-foreground flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-hidden disabled:cursor-not-allowed disabled:opacity-50;
}
}
-
- /* Combobox */
[role='listbox']:not(:has([data-value]:not([aria-hidden='true'])))::before {
@apply flex items-center justify-center p-6 text-sm truncate;
}
diff --git a/docs/_includes/partials/kitchen-sink/combobox.njk b/docs/_includes/partials/kitchen-sink/combobox.njk
index cb56a53..f1a04b5 100644
--- a/docs/_includes/partials/kitchen-sink/combobox.njk
+++ b/docs/_includes/partials/kitchen-sink/combobox.njk
@@ -5,63 +5,76 @@
Combobox
- {% set options_timezones = [
- {
- label: "Americas",
- timezones: [
- { value: "America/New_York", label: "(GMT-5) New York" },
- { value: "America/Los_Angeles", label: "(GMT-8) Los Angeles" },
- { value: "America/Chicago", label: "(GMT-6) Chicago" },
- { value: "America/Toronto", label: "(GMT-5) Toronto" },
- { value: "America/Vancouver", label: "(GMT-8) Vancouver" },
- { value: "America/Sao_Paulo", label: "(GMT-3) São Paulo" }
- ]
- },
- {
- label: "Europe",
- timezones: [
- { value: "Europe/London", label: "(GMT+0) London" },
- { value: "Europe/Paris", label: "(GMT+1) Paris" },
- { value: "Europe/Berlin", label: "(GMT+1) Berlin" },
- { value: "Europe/Rome", label: "(GMT+1) Rome" },
- { value: "Europe/Madrid", label: "(GMT+1) Madrid" },
- { value: "Europe/Amsterdam", label: "(GMT+1) Amsterdam" }
- ]
- },
- {
- label: "Asia/Pacific",
- timezones: [
- { value: "Asia/Tokyo", label: "(GMT+9) Tokyo" },
- { value: "Asia/Shanghai", label: "(GMT+8) Shanghai" },
- { value: "Asia/Singapore", label: "(GMT+8) Singapore" },
- { value: "Asia/Dubai", label: "(GMT+4) Dubai" },
- { value: "Australia/Sydney", label: "(GMT+11) Sydney" },
- { value: "Asia/Seoul", label: "(GMT+9) Seoul" }
- ]
- }
- ] %}
- {% call select(
- content_attrs={"class": "w-72"},
- listbox_attrs={"data-empty": "No timezone found."},
- is_combobox=true
- ) %}
-
- {% for group in options_timezones %}
-
-
{{ group.label }}
- {% for timezone in group.timezones %}
-
- {{ timezone.label }}
-
- {% endfor %}
-
+
+ {% set options_frameworks = ["Next.js", "SvelteKit", "Nuxt.js", "Remix", "Astro"] %}
+ {% call select(
+ content_attrs={"class": "w-48"},
+ listbox_attrs={"data-empty": "No framework found."},
+ is_combobox=true
+ ) %}
+ {% for framework in options_frameworks %}
+
{{ framework }}
{% endfor %}
-
-
-
- {% lucide "circle-plus" %}
- Create timezone
-
- {% endcall %}
+ {% endcall %}
+
+ {% set options_timezones = [
+ {
+ label: "Americas",
+ timezones: [
+ { value: "America/New_York", label: "(GMT-5) New York" },
+ { value: "America/Los_Angeles", label: "(GMT-8) Los Angeles" },
+ { value: "America/Chicago", label: "(GMT-6) Chicago" },
+ { value: "America/Toronto", label: "(GMT-5) Toronto" },
+ { value: "America/Vancouver", label: "(GMT-8) Vancouver" },
+ { value: "America/Sao_Paulo", label: "(GMT-3) São Paulo" }
+ ]
+ },
+ {
+ label: "Europe",
+ timezones: [
+ { value: "Europe/London", label: "(GMT+0) London" },
+ { value: "Europe/Paris", label: "(GMT+1) Paris" },
+ { value: "Europe/Berlin", label: "(GMT+1) Berlin" },
+ { value: "Europe/Rome", label: "(GMT+1) Rome" },
+ { value: "Europe/Madrid", label: "(GMT+1) Madrid" },
+ { value: "Europe/Amsterdam", label: "(GMT+1) Amsterdam" }
+ ]
+ },
+ {
+ label: "Asia/Pacific",
+ timezones: [
+ { value: "Asia/Tokyo", label: "(GMT+9) Tokyo" },
+ { value: "Asia/Shanghai", label: "(GMT+8) Shanghai" },
+ { value: "Asia/Singapore", label: "(GMT+8) Singapore" },
+ { value: "Asia/Dubai", label: "(GMT+4) Dubai" },
+ { value: "Australia/Sydney", label: "(GMT+11) Sydney" },
+ { value: "Asia/Seoul", label: "(GMT+9) Seoul" }
+ ]
+ }
+ ] %}
+ {% call select(
+ content_attrs={"class": "w-72"},
+ listbox_attrs={"data-empty": "No timezone found."},
+ is_combobox=true
+ ) %}
+
+
+
+ {% lucide "circle-plus" %}
+ Create timezone
+
+ {% endcall %}
+
\ No newline at end of file
diff --git a/docs/components/accordion.njk b/docs/components/accordion.njk
index 33c7327..4092dd4 100644
--- a/docs/components/accordion.njk
+++ b/docs/components/accordion.njk
@@ -7,12 +7,14 @@ toc:
id: usage
---
+{% from "macros/code_preview.njk" import code_preview %}
+{% from "macros/code_block.njk" import code_block %}
+
{% lucide "circle-alert" %}
There is no dedicated accordion component in Basecoat.
-{% from "macros/code_preview.njk" import code_preview %}
{% set code %}Usage
- Basecoat animates <details> elements by default. The example above shows how to use Alpine.js, Tailwind and <details> elements to implement a simple accordion.
-
\ No newline at end of file
+ Basecoat animates <details> elements by default. Using Alpine.js to handle the open/close state and Tailwind to style the the <details> elements, you can get an accordion component:
+
+
+{{ code_block(code) }}
\ No newline at end of file
diff --git a/docs/components/alert-dialog.njk b/docs/components/alert-dialog.njk
index d87809f..88afc5d 100644
--- a/docs/components/alert-dialog.njk
+++ b/docs/components/alert-dialog.njk
@@ -50,7 +50,7 @@ toc:
- If you use Jinja (or Nunjucks), you can use the Dialog macro directly, making sure to set close_on_overlay_click to False (or false for Nunjucks).
+ If you use Jinja (or Nunjucks), you can use the dialog() macro directly, making sure to set close_on_overlay_click to False (or false for Nunjucks).
+
+{{ code_block(code | prettyHtml) }}
\ No newline at end of file
diff --git a/docs/components/combobox.njk b/docs/components/combobox.njk
new file mode 100644
index 0000000..bfd7c19
--- /dev/null
+++ b/docs/components/combobox.njk
@@ -0,0 +1,138 @@
+---
+layout: layouts/component.njk
+title: Combobox
+description: Autocomplete input and command palette with a list of suggestions.
+toc:
+ - label: Usage
+ id: usage
+ children:
+ - label: Default
+ id: usage-default
+ - label: Jinja or Nunjucks
+ id: usage-jinja
+ - label: Examples
+ id: examples
+ children:
+ - label: With groups
+ id: example-with-groups
+---
+
+{% from "macros/code_preview.njk" import code_preview %}
+{% from "macros/code_block.njk" import code_block %}
+{% from "components/select.njk" import select %}
+
+{% set options_frameworks = ["Next.js", "SvelteKit", "Nuxt.js", "Remix", "Astro"] %}
+{% set code %}
+{% call select(
+ trigger_attrs={"class": "w-[200px]"},
+ listbox_attrs={"data-empty": "No framework found."},
+ is_combobox=true
+) %}
+ {% for framework in options_frameworks %}
+ {{ framework }}
+ {% endfor %}
+{% endcall %}{% endset %}
+{{ code_preview("combobox", code | prettyHtml) }}
+
+
+
+
+
+
+ The Combobox component uses the same Alpine.js code as the Select component, and almost identical markup, the only difference being the search box.
+
+
+{{ code_block(code | prettyHtml) }}
+
+
+
+
+ If you use Jinja (or Nunjucks), you can use the select() macro directly, making sure to set is_combobox to True (or true for Nunjucks).
+
+
+
+{% set raw_code %}{% raw %}{% call select(
+ listbox_attrs={"data-empty": "No framework found."},
+ is_combobox=true
+) %}
+ Next.js
+ SvelteKit
+ Nuxt.js
+ Remix
+ Astro
+{% endcall %}{% endraw %}{% endset %}
+{{ code_block(raw_code, "jinja") }}
+
+
+
+
+
+{% set options_timezones = [
+ {
+ label: "Americas",
+ timezones: [
+ { value: "America/New_York", label: "(GMT-5) New York" },
+ { value: "America/Los_Angeles", label: "(GMT-8) Los Angeles" },
+ { value: "America/Chicago", label: "(GMT-6) Chicago" },
+ { value: "America/Toronto", label: "(GMT-5) Toronto" },
+ { value: "America/Vancouver", label: "(GMT-8) Vancouver" },
+ { value: "America/Sao_Paulo", label: "(GMT-3) São Paulo" }
+ ]
+ },
+ {
+ label: "Europe",
+ timezones: [
+ { value: "Europe/London", label: "(GMT+0) London" },
+ { value: "Europe/Paris", label: "(GMT+1) Paris" },
+ { value: "Europe/Berlin", label: "(GMT+1) Berlin" },
+ { value: "Europe/Rome", label: "(GMT+1) Rome" },
+ { value: "Europe/Madrid", label: "(GMT+1) Madrid" },
+ { value: "Europe/Amsterdam", label: "(GMT+1) Amsterdam" }
+ ]
+ },
+ {
+ label: "Asia/Pacific",
+ timezones: [
+ { value: "Asia/Tokyo", label: "(GMT+9) Tokyo" },
+ { value: "Asia/Shanghai", label: "(GMT+8) Shanghai" },
+ { value: "Asia/Singapore", label: "(GMT+8) Singapore" },
+ { value: "Asia/Dubai", label: "(GMT+4) Dubai" },
+ { value: "Australia/Sydney", label: "(GMT+11) Sydney" },
+ { value: "Asia/Seoul", label: "(GMT+9) Seoul" }
+ ]
+ }
+] %}
+{% set code %}
+{% call select(
+ trigger_attrs={"class": "w-[200px]"},
+ content_attrs={"class": "w-72"},
+ listbox_attrs={"data-empty": "No timezone found."},
+ is_combobox=true
+) %}
+
+
+
+ {% lucide "circle-plus" %}
+ Create timezone
+
+{% endcall %}
+{% endset %}
+{{ code_preview("combobox-with-groups", code | prettyHtml) }}
diff --git a/docs/components/popover.njk b/docs/components/popover.njk
index 038d0f6..0cdfd66 100644
--- a/docs/components/popover.njk
+++ b/docs/components/popover.njk
@@ -2,16 +2,108 @@
layout: layouts/component.njk
title: Popover
description: Displays rich content in a portal, triggered by a button.
+toc:
+ - label: Usage
+ id: usage
+ children:
+ - label: Default
+ id: usage-default
+ - label: Jinja or Nunjucks
+ id: usage-jinja
---
-
- {% lucide "info" %}
-
There is no dedicated avatar component in Basecoat.
-
-
-
+{% from "macros/code_preview.njk" import code_preview %}
{% from "macros/code_block.njk" import code_block %}
-{% set code %} {% endset %}
-{{ code_block("accordion", code, "max-w-md") }}
\ No newline at end of file
+{% from "components/popover.njk" import popover %}
+
+{% set code %}
+{% call popover(
+ id="demo-popover",
+ trigger="Open popover",
+ trigger_attrs={"class": "btn-outline"},
+ content_attrs={"class": "w-80 p-4"}
+) %}
+
+{% endcall %}
+{% endset %}
+{{ code_preview("popover", code | prettyHtml ) }}
+
+
+
+
+
+
+ If you need to do more than what <select> allows (e.g. HTML options), you can use the code below which uses the Popover component. Make sure to include the hidden input with the name you want to use for that field.
+
+
+{{ code_block(code | prettyHtml) }}
+
+
+
+
+ If you use Jinja (or Nunjucks), you can use the popover() macro directly.
+
+
+
+{% set raw_code %}{% raw %}{% call popover(
+ id="demo-popover",
+ trigger="Open popover",
+ trigger_attrs={"class": "btn-outline"},
+ content_attrs={"class": "w-80 p-4"}
+) %}
+
+{% endcall %}{% endraw %}{% endset %}
+{{ code_block(raw_code, "jinja") }}
\ No newline at end of file
diff --git a/docs/components/select.njk b/docs/components/select.njk
index cc5118e..67801f9 100644
--- a/docs/components/select.njk
+++ b/docs/components/select.njk
@@ -1,14 +1,141 @@
---
layout: layouts/component.njk
title: Select
-description: isplays a list of options for the user to pick from—triggered by a button.
+description: Displays a list of options for the user to pick from—triggered by a button.
+toc:
+ - label: Usage
+ id: usage
+ children:
+ - label: Default
+ id: usage-default
+ - 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 %}
-{% set code %}
- Success
-
-
{% endset %}
-{{ code_block("accordion", code, "max-w-md") }}
+{% from "components/select.njk" import select %}
-Usage
+{% set code_native %}
+
+ Apple
+ Banana
+ Blueberry
+ Grapes
+ Pineapple
+ {% endset %}
+{{ code_preview("select-native", code_native) }}
+
+{% set code_alpine %}
+{% call select(name="select-js", trigger_attrs={"class": "w-[180px]"}) %}
+
+
Fruits
+
Apple
+
Banana
+
Blueberry
+
Grapes
+
Pineapple
+
+{% endcall %}
+{% endset %}
+{{ code_preview("select-alpine", code_alpine | prettyHtml) }}
+
+
+
+
+
+
+ If you use a <select> element, just add the select class to it or have a parent with the form class (read more about form ).
+
+
+{{ code_block(code_native) }}
+
+
+
+
+ If you need to do more than what <select> allows (e.g. HTML options), you can use the code below which uses the Popover component. Make sure to include the hidden input with the name you want to use for that field.
+
+
+{{ code_block(code_alpine | prettyHtml) }}
+
+
+
+
+ If you use Jinja (or Nunjucks), you can use the select() macro directly.
+
+
+
+{% set raw_code %}{% raw %}{% call select(name="select-js") %}
+
+
Fruits
+
Apple
+
Banana
+
Blueberry
+
Grapes
+
Pineapple
+
+{% endcall %}{% endraw %}{% endset %}
+{{ code_block(raw_code, "jinja") }}
+
+
+
+
+
+{% set code %}
+{% call select(
+ listbox_attrs={"class": "scrollbar overflow-y-auto max-h-64"}
+) %}
+{% for i in range(0, 99) %}
+Item {{ i }}
+{% endfor %}
+{% endcall %}
+{% endset %}
+
+{{ code_preview("select-scrollable", code | prettyHtml) }}
+
+
+
+{% set code %}
+{% call select(trigger_attrs={"disabled": "disabled"}) %}
+Disabled
+{% endcall %}
+{% endset %}
+
+{{ code_preview("select-disabled", code | prettyHtml) }}
+
+
+
+{% set code %}
+{% call select(trigger_attrs={'class': 'w-[180px]'}) %}
+
+ {% lucide "chart-bar", {"class": "text-muted-foreground"} %}
+ Bar
+
+
+ {% lucide "chart-line", {"class": "text-muted-foreground"} %}
+ Line
+
+
+ {% lucide "chart-pie", {"class": "text-muted-foreground"} %}
+ Pie
+
+{% endcall %}
+{% endset %}
+
+{{ code_preview("select-scrollable", code | prettyHtml) }}
\ No newline at end of file