Skip to content

Popover ​

Source ​

Example ​

Vanilla Popover ​

html
<div class="x-popover focus">
    <div role="button" class="x-button" tabindex="0">Toggle Popover</div>
    <div class="x-popover-content center shadow dark:bg-body-secondary mt-2.5 p-2 w-32 flex-col">
        Popover content
    </div>
</div>

Javascript Popover ​

Leverages the Popover API with floating-ui.

html
<div
    class="x-popover"
    data-controller="x-popover"
>
    <button
        class="x-button"
        role="button"
        popovertargetaction="toggle"
        popovertarget="popoverElement"
        id="popoverAction"
    >Toggle Popover</button>
    
    <div class="x-popover-content shadow h-48" id="popoverElement" aria-describedby="popoverAction" popover="manual">
        Popover content
        <button
            type="button"
            data-action="x-popover#hide"
        >x</button>
    </div>
</div>

Autocomplete Popover ​

Preview ​

Source ​

html
<div class="x-popover trigger-focus group mx-auto w-80" data-controller="x-popover">
    <div class="x-control w-full">
        <input
            data-action="input->x-popover#autocomplete"
            data-x-popover-target="autocomplete"
            type="search"
            placeholder="Vyhledávání ..."
            autocomplete="off"
            role="combobox"
            aria-autocomplete="list"
            aria-controls="popoverContent"
            aria-haspopup="listbox"
            aria-expanded="true"
            value="Volba"
        >
    </div>
    <div
        class="x-popover-content center flex flex-col shadow dark:bg-body-secondary mt-2 p-2 gap-2 w-full empty:closed group-not-has-aria-expanded:closed"
        data-x-popover-target="content"
        role="listbox"
        id="popoverContent"
    >
        <button id="option-1" class="x-button ghosted justify-start" role="option" data-action="click->x-popover#selectDescendant">Volba 1</button>
        <button id="option-2" class="x-button ghosted justify-start" role="option" data-action="click->x-popover#selectDescendant">Volba 2</button>
        <button id="option-3" class="x-button ghosted justify-start" role="option" data-action="click->x-popover#selectDescendant">Volba 3</button>
    </div>
</div>

More examples can be found in the Winduum docs.

Example CSS ​

css
@import "winduum/src/components/popover/props/content.css" layer(theme);
@import "winduum/src/components/popover/content.css" layer(utilities);
@import "winduum/src/components/popover/default.css" layer(utilities);

/* Example customization */
@layer utilities {
  .x-popover {
    --x-popover-content-background-color: var(--color-accent);
    --x-popover-content-border-radius: var(--radius-md);
  }
}

Winduum CSS Code ​

winduum/src/components/popover/props/content.css ​

css
:root,
:host {
  --x-popover-content-background-color: var(--color-body-primary);
  --x-popover-content-border-radius: var(--radius-xl);
  --x-popover-content-padding-block: calc(var(--spacing) * 2);
  --x-popover-content-padding-inline: calc(var(--spacing) * 2);
  --x-popover-content-scale-y: 0.75;
  --x-popover-content-scale-x: 0.75;
}

winduum/src/components/popover/content.css ​

css
.x-popover-content {
  background-color: var(--x-popover-content-background-color);
  border-radius: var(--x-popover-content-border-radius);
  padding: var(--x-popover-content-padding-block) var(--x-popover-content-padding-inline);
  z-index: var(--x-popover-content-z-index, var(--z-index-10));
  transition-property: var(--default-transition-property);
  transition-timing-function: var(--ease-in-out);
  transition-duration: var(--default-transition-duration);
  transform:
    translate(var(--tw-translate-x, 0), var(--tw-translate-y, 0))
    scaleX(var(--tw-scale-x, 1)) scaleY(var(--tw-scale-y, 1));
  will-change: transform;
  inline-size: max-content;
  position: absolute;

  &:where(.bottom),
  & {
    transform-origin: top;
  }

  &:where(.bottom-start) {
    transform-origin: top left;
  }

  &:where(.bottom-end) {
    inset-inline-end: 0;
    transform-origin: top right;
  }

  &:where(.right) {
    inset-block-start: 0;
    inset-inline-start: 100%;
    transform-origin: left;
  }

  &:where(.right-start) {
    transform-origin: left top;
  }

  &:where(.right-end) {
    inset-block: auto 0;
    transform-origin: left bottom;
  }

  &:where(.left) {
    inset-block-start: 0;
    inset-inline-end: 100%;
    transform-origin: right;
  }

  &:where(.left-start) {
    transform-origin: right top;
  }

  &:where(.left-end) {
    inset-block: auto 0;
    transform-origin: right bottom;
  }

  &:where(.top) {
    inset-block-end: 100%;
    transform-origin: bottom;
  }

  &:where(.top-start) {
    transform-origin: bottom left;
  }

  &:where(.top-end) {
    inset-inline-end: 0;
    transform-origin: bottom right;
  }

  &:where(.inline-center) {
    --tw-translate-x: -50%;

    inset-inline-start: 50%;
  }

  &:where(.block-center) {
    --tw-translate-y: -50%;

    inset-block-start: 50%;
  }

  &[popover]:not([data-open]) {
    --tw-scale-x: var(--x-popover-content-scale-x);
    --tw-scale-y: var(--x-popover-content-scale-y);

    opacity: 0%;
    pointer-events: none;
  }

  &:not([popover]) {
    .trigger-focus:not(:focus, :focus-within) > &,
    .trigger-hover:not(:hover) > & {
      --tw-scale-x: var(--x-popover-content-scale-x);
      --tw-scale-y: var(--x-popover-content-scale-y);

      opacity: 0%;
      visibility: hidden;
    }
  }
}

winduum/src/components/popover/default.css ​

css
.x-popover {
  position: relative;
  display: inline-block;
}

Stimulus Actions ​

toggle ​

Action is automatically added on first [popovertargetaction] element upon controller connection, if it exists.

html
<button 
    class="x-button" 
    role="button" 
    popovertargetaction="toggle" 
    data-action="click->x-popover#toggle:prevent keydown.esc@window->x-popover#hide click@window->x-popover#dismiss click->invoke-ripple#show" 
    popovertarget="_6zbalmci_" 
    aria-expanded="false" 
    aria-haspopup="dialog"
>
    Toggle Popover
</button>

show ​

Action is automatically added on first [popovertargetaction] element upon controller connection, if it exists.

hide ​

Action is automatically added on first [popovertargetaction] element upon controller connection, if it exists.

html
    <div class="x-popover-content shadow h-48" id="popoverElement" aria-describedby="popoverAction" popover="manual">
        Popover content
        <button
            type="button"
            data-action="x-popover#hide"
        >x</button>
    </div>

dismiss ​

Action is automatically added on first [popovertargetaction] element upon controller connection as click@window->x-popover#dismiss, if it exists.

fetch ​

Fetches the popover remotely, used internally.

onFetchComplete ​

Callback that is executed after fetch is complete.

Stimulus Values ​

url ​

Fetches the popover remotely, popovertarget is added dynamically upon completed request.

html
    <div
        class="x-popover"
        data-controller="x-popover"
        data-x-popover-url-value="/popover/info.json"
    >
        <button
            class="x-button"
            role="button"
            popovertargetaction="toggle"
            id="popoverAction"
        >Fetch Popover</button>
    </div>

appendTo ​

Choose a selector where to append the popover after a fetch. Defaults to position after the trigger element of the popover.

html
    <div
        class="x-popover"
        data-controller="x-popover"
        data-x-popover-url-value="/popover/info.json"
        data-x-popover-append-to-value="body"
        id="popoverAction"
    >
        <button
            class="x-button"
            role="button"
            popovertargetaction="toggle"
        >Fetch Popover</button>
    </div>

manual ​

Disables automatic generation of action values to [popovertargetaction] element upon controller connection.

html
<div
    class="x-popover"
    data-controller="x-popover"
    data-x-popover-manual-value="true"
>
    <button
        class="x-button"
        role="button"
        popovertargetaction="toggle"
        popovertarget="popoverElement"
    >Toggle Popover</button>
</div>

Released under the MIT License.