<script>
window.basecoat = window.basecoat || {};
window.basecoat.registerPopover = function (Alpine) {
if (Alpine.components && Alpine.components.popover) return;
Alpine.data("popover", () => ({
open: false,
$trigger: {
"@click"() {
this.open = !this.open;
},
"@keydown.escape.prevent"() {
this.open = false;
this.$refs.trigger.focus();
},
":aria-expanded"() {
return this.open;
},
"x-ref": "trigger",
},
$content: {
"@keydown.escape.prevent"() {
this.open = false;
this.$refs.trigger.focus();
},
":aria-hidden"() {
return !this.open;
},
"x-cloak": "",
},
}));
};
document.addEventListener("alpine:init", () => {
window.basecoat.registerPopover(Alpine);
});
</script>
<div class="popover" x-data="popover" @click.away="open = false" id="demo-popover">
<button type="button" aria-haspopup="menu" aria-expanded="false" x-bind="$trigger" id="demo-popover-trigger" aria-controls="demo-popover-menu" class="btn-outline">Open popover</button>
<div data-popover aria-hidden="true" x-bind="$content" id="demo-popover-menu" class="w-80 p-4">
<div class="grid gap-4">
<header class="grid gap-1.5">
<h4 class="leading-none font-medium">Dimensions</h4>
<p class="text-muted-foreground text-sm">Set the dimensions for the layer.</p>
</header>
<form class="form grid gap-2">
<div class="grid grid-cols-3 items-center gap-4">
<label for="demo-popover-width">Width</label>
<input type="text" id="demo-popover-width" value="100%" class="col-span-2 h-8" />
</div>
<div class="grid grid-cols-3 items-center gap-4">
<label for="demo-popover-max-width">Max. width</label>
<input type="text" id="demo-popover-max-width" value="300px" class="col-span-2 h-8" />
</div>
<div class="grid grid-cols-3 items-center gap-4">
<label for="demo-popover-height">Height</label>
<input type="text" id="demo-popover-height" value="25px" class="col-span-2 h-8" />
</div>
<div class="grid grid-cols-3 items-center gap-4">
<label for="demo-popover-max-height">Max. height</label>
<input type="text" id="demo-popover-max-height" value="none" class="col-span-2 h-8" />
</div>
</form>
</div>
</div>
</div>
Usage
HTML + Javascript
This component requires Javascript.
The component is structured as such:
- A
<div class="popover">
which wraps around the entire component and holds it state (e.g. open/close). - A
<button>
that acts as the trigger to open or close the popover. - A
<div data-popover>
that holds the content of the popover.
You can set up a few additional options on the <div data-popover>
element:
data-side
can be set totop
,bottom
,left
, orright
to change the side of the popover.data-align
can be set tostart
,center
, orend
to change the alignment of the popover.
You can include the Javascript code provided below, load it as an individual file or use the CLI. Some Alpine.js properties are also required on certain elements (e.g. x-bind
, x-data
, @click
).
<div class="popover" x-data="popover" @click.away="open = false" id="demo-popover">
<button type="button" aria-haspopup="menu" aria-expanded="false" x-bind="$trigger" id="demo-popover-trigger" aria-controls="demo-popover-menu" class="btn-outline">Open popover</button>
<div data-popover aria-hidden="true" x-bind="$content" id="demo-popover-menu" class="w-80 p-4">
<div class="grid gap-4">
<header class="grid gap-1.5">
<h4 class="leading-none font-medium">Dimensions</h4>
<p class="text-muted-foreground text-sm">Set the dimensions for the layer.</p>
</header>
<form class="form grid gap-2">
<div class="grid grid-cols-3 items-center gap-4">
<label for="demo-popover-width">Width</label>
<input type="text" id="demo-popover-width" value="100%" class="col-span-2 h-8" />
</div>
<div class="grid grid-cols-3 items-center gap-4">
<label for="demo-popover-max-width">Max. width</label>
<input type="text" id="demo-popover-max-width" value="300px" class="col-span-2 h-8" />
</div>
<div class="grid grid-cols-3 items-center gap-4">
<label for="demo-popover-height">Height</label>
<input type="text" id="demo-popover-height" value="25px" class="col-span-2 h-8" />
</div>
<div class="grid grid-cols-3 items-center gap-4">
<label for="demo-popover-max-height">Max. height</label>
<input type="text" id="demo-popover-max-height" value="none" class="col-span-2 h-8" />
</div>
</form>
</div>
</div>
</div>
<script>
window.basecoat = window.basecoat || {};
window.basecoat.registerPopover = function (Alpine) {
if (Alpine.components && Alpine.components.popover) return;
Alpine.data("popover", () => ({
open: false,
$trigger: {
"@click"() {
this.open = !this.open;
},
"@keydown.escape.prevent"() {
this.open = false;
this.$refs.trigger.focus();
},
":aria-expanded"() {
return this.open;
},
"x-ref": "trigger",
},
$content: {
"@keydown.escape.prevent"() {
this.open = false;
this.$refs.trigger.focus();
},
":aria-hidden"() {
return !this.open;
},
"x-cloak": "",
},
}));
};
document.addEventListener("alpine:init", () => {
window.basecoat.registerPopover(Alpine);
});
</script>
Jinja and Nunjucks
You can use the popover()
Nunjucks or Jinja macro for this component.
{% call popover(
id="demo-popover",
trigger="Open popover",
trigger_attrs={"class": "btn-outline"},
content_attrs={"class": "w-80 p-4"},
register_on=["alpine:init", "htmx:afterSwap"]
) %}
<div class="grid gap-4">
<header class="grid gap-1.5">
<h4 class="leading-none font-medium">Dimensions</h4>
<p class="text-muted-foreground text-sm">Set the dimensions for the layer.</p>
</header>
<form class="form grid gap-2">
<div class="grid grid-cols-3 items-center gap-4">
<label for="demo-popover-width">Width</label>
<input type="text" id="demo-popover-width" value="100%" class="col-span-2 h-8"/>
</div>
<div class="grid grid-cols-3 items-center gap-4">
<label for="demo-popover-max-width">Max. width</label>
<input type="text" id="demo-popover-max-width" value="300px" class="col-span-2 h-8"/>
</div>
<div class="grid grid-cols-3 items-center gap-4">
<label for="demo-popover-height">Height</label>
<input type="text" id="demo-popover-height" value="25px" class="col-span-2 h-8"/>
</div>
<div class="grid grid-cols-3 items-center gap-4">
<label for="demo-popover-max-height">Max. height</label>
<input type="text" id="demo-popover-max-height" value="none" class="col-span-2 h-8"/>
</div>
</form>
</div>
{% endcall %}