Popovers

Popovers are components that overlay on above of the interface. Popovers can contain a mix of information. Popovers are used to inform customers about specific content and actions.

Position: above, below, leading, or trailing

Levicorpus

Causes a person to hang upside-down in midair as if hoisted by the ankle.

Wingardium Leviosa

A charm that can levitate things.

Alohomora

A spell to open locks; aka "the thief's friend."

Lumos

A handy piece of magic that can turn a wand into a torch.

<button
  aria-expanded="false"
  class="btn btn--primary mb-2x"
  id="popoverTrigger1"
  onClick="togglePopover(popoverTrigger1, popover1)"
  type="button"
>
  Above (Default)
</button>
<tk-v2-popover
  id="popover1"
>
  <h3 slot="header">Levicorpus</h3>
  <p>Causes a person to hang upside-down in midair as if hoisted by the ankle.</p>
</tk-v2-popover>

<!-- Example: Below -->
<button
  aria-expanded="false"
  class="btn btn--primary mb-2x"
  id="popoverTrigger2"
  onClick="togglePopover(popoverTrigger2, popover2)"
  type="button"
>
  Below
</button>
<tk-v2-popover
  id="popover2"
  position="below"
>
  <h3 slot="header">Wingardium Leviosa</h3>
  <p>A charm that can levitate things.</p>
</tk-v2-popover>

<!-- Example: Leading -->
<button
  aria-expanded="false"
  class="btn btn--primary mb-2x"
  id="popoverTrigger3"
  onClick="togglePopover(popoverTrigger3, popover3)"
  type="button"
>
  Leading
</button>
<tk-v2-popover
  id="popover3"
  position="leading"
>
  <h3 slot="header">Alohomora</h3>
  <p>A spell to open locks; aka "the thief's friend."</p>
</tk-v2-popover>

<!-- Example: Trailing -->
<button
  aria-expanded="false"
  class="btn btn--primary mb-2x"
  id="popoverTrigger4"
  onClick="togglePopover(popoverTrigger4, popover4)"
  type="button"
>
  Trailing
</button>
<tk-v2-popover
  id="popover4"
  position="trailing"
>
  <h3 slot="header">Lumos</h3>
  <p>A handy piece of magic that can turn a wand into a torch.</p>
</tk-v2-popover>

<!-- Script is only necessary in non-framework uses. Otherwise, you can add the eventListener directly tk-v2-popover, and add the target attribute with a value of the trigger element ref. -->
<script>
  popover1.target = popoverTrigger1;
  popover2.target = popoverTrigger2;
  popover3.target = popoverTrigger3;
  popover4.target = popoverTrigger4;

  const togglePopover = (trigger, popover) => {
    trigger.setAttribute('aria-expanded', !popover.open);
    popover.open = !popover.open;
  }

  popover1.addEventListener('close', () => togglePopover(popoverTrigger1, popover1));
  popover2.addEventListener('close', () => togglePopover(popoverTrigger2, popover2));
  popover3.addEventListener('close', () => togglePopover(popoverTrigger3, popover3));
  popover4.addEventListener('close', () => togglePopover(popoverTrigger4, popover4));
</script>

Description

There are 4 positions for displaying a popover in relation to its trigger: above (default), below, leading, or trailing.

📐 Position

Position is treated as a preference. If there isn’t enough space in the viewport, it will automatically attempt to display in a position that fits. It will also try to center it, if space allows. See full-page examples: above, below, leading, or trailing.

🗒 Usage

Setting the open Prop on the popover controls visibility. It requires a target to be set as well: this tells the popover which element is its “anchor.” The popover will emit an event (close) when esc is pressed, or when there is a click outside of the popover.

⚠️ Important

Please add an event handler for the close event that then sets the open Prop to false. This is needed for accessibility and UX reasons. Also, set the aria-expanded state on the trigger.

When using within an existing JS framework, such as Angular, you can simplify this quite a bit:

<button
  #popoverTrigger1
  type="button"
  [attr.aria-expanded]="popoverVisible$ | async"
  (click)="popoverVisible$.next(!popoverVisible$.getValue())"
>Button</button>
<tk-v2-popover
  #popover1
  [attr.open]="popoverVisible$ | async"
  [attr.target]="#popoverTrigger1"
  (close)="popoverVisible$.next(false)"
>Content</tk-v2-popover>

Size: default or large

We could all have been killed - or worse, expelled

Summon an object. If the object is protected, then it won't be retrieved. In his seventh year, George Weasley successfully summoned his broom from Dolores Umbridge's office when escaping Hogwarts. ⚡️

  • List no 1
  • List no 2
  • List no 3
  • List no 4
  • List no 5
  • List no 6
  • List no 7
  • List no 8
<button
  aria-expanded="false"
  class="btn btn--primary"
  id="popoverSizeExampleTrigger"
  onClick="toggleSizePopover(popoverSizeExampleTrigger, popoverSizeExample)"
  type="button"
>
  Large
</button>
<tk-v2-popover
  id="popoverSizeExample"
  size="large"
>
  <div class="l-flex l-v-center" slot="header">
    <h2 class="t-heavy">We could all have been killed - or worse, expelled</h2>
    <button class="btn--primary ml-auto t-xs ml-auto" type="button">Wingardium Leviosa</button>
  </div>
  <div style="max-height: 100px">
    <p>Summon an object. If the object is protected, then it won't be retrieved. In his seventh year, George Weasley successfully summoned his broom from Dolores Umbridge's office when escaping Hogwarts. ⚡️</p>
    <ul>
      <li>List no 1</li>
      <li>List no 2</li>
      <li>List no 3</li>
      <li>List no 4</li>
      <li>List no 5</li>
      <li>List no 6</li>
      <li>List no 7</li>
      <li>List no 8</li>
    </ul>
  </div>
</tk-v2-popover>

<!-- Script is only necessary in non-framework uses. Otherwise, you can add the eventListener directly to the element. -->
<script>
  popoverSizeExample.target = popoverSizeExampleTrigger;
  const toggleSizePopover = (trigger, popover) => {
    trigger.setAttribute('aria-expanded', !popover.open);
    popover.open = !popover.open;
  }
  popoverSizeExample.addEventListener('close', () => toggleSizePopover(popoverSizeExampleTrigger, popoverSizeExample));
</script>

Icon-only example

Full Body-Bind Curse; temporarily binds the victim’s entire body, thus immobilizing him or her.

<button
  aria-expanded="false"
  aria-label="Read more information"
  class="btn t-link"
  id="popoverTriggerIcon"
  onClick="toggleIconPopover(popoverTriggerIcon, popoverIcon)"
  type="button"
>
  <tk-icon
    name="question-mark-circle"
    size="small"
  ></tk-icon>
</button>
<tk-v2-popover
  id="popoverIcon"
>
  <p>Full Body-Bind Curse; temporarily binds the victim’s entire body, thus immobilizing him or her.</p>
</tk-v2-popover>

<!-- Script is only necessary in non-framework uses. Otherwise, you can add the eventListener directly to the element. -->
<script>
  popoverIcon.target = popoverTriggerIcon;
  const toggleIconPopover = (trigger, popover) => {
    trigger.setAttribute('aria-expanded', !popover.open);
    popover.open = !popover.open;
  }
  popoverIcon.addEventListener('close', () => toggleIconPopover(popoverTriggerIcon, popoverIcon));
</script>

Description

Please remember to add an aria-label to describe the icon’s intent to people using assistive technology.

Props

Property Options Default Description
open false Sets the visibility of the popover.
position above, below, leading, trailing above Sets the preferred position of the popover. If the preference causes the popover to be out-of-bounds, then the popover will auto-position itself.
size default, large default Sets the size of the popover.
target HTMLElement Element that the popover should anchor itself to.

Events

Name Description
close Emitted whenever esc is pressed, or a click is outside of the popover and its trigger.

Usage

Do

  • Clearly title popovers when applicable
  • Use clear and concise language

Don't

  • Overlap popovers

Accessibility

  • Popover trigger should have an aria-expanded attribute that is dynamically set when the open Prop is true.
  • There should only be one id per page.