Accessibility Examples: Popover Widget

A popover is a disclosure pattern (i.e. hide/show widget) styled to appear as a tooltip. Popover widgets allow for more content than would be appropriate for a tooltip and for the inclusion of interactive elements, such as links (tooltips are not focusable). Modal dialog widgets should be used when the pop-up information must be acknowledged by the user.

Popover Example

A popover widget allows for interactive content to appear in a pop-up widget.

Popovers may be triggered from text that is made focusable, or any typically interactive page element; i.e. buttons, links, other form controls), and they may be positioned in any way that makes sense for the information:

left top right below

Required HTML Markup

A popover must indicate if it is expanded (visible) or collapsed (hidden) and the trigger for the popover must be associated with the popover region to be displayed.

Below is a code snippet showing simplified markup for implementing an accessible popover widget.

<span class="a11y-popover-wrap">
   <span id="popover1" aria-expanded="false" role="button" tabindex="0">Popover</span>
   <span id="popover1-reg"aria-labelledby="popover1" role="region">
      . . .
   </span>
</span>
   

Note: Any logical containing element may be used for the popover trigger. The snippet above assumes that the trigger is a string of text within a larger paragraph. An html button or link could have been used as well. If the trigger element is not an html button, the button role must be added.

Note: The use of the aria-labelledby property and region role on the popover region is not part of the ARIA specification for a disclosure widget. These attributes are used to clearly demarcate the contents of the popover region and to associate the region with its triggering element, e.g. give it a useful label. If the popover region contains a heading, then these attributes may be omitted. Also, the use of the region role should be omitted when it would result in region proliferation, i.e. when multiple popover regions (more than 6) will likely be displayed simultaneously.

Dynamic Markup Generation

To simplify page markup, the popover markup may be generated dynamically, with the region's content stored in an HTML5 data attribute. The aria-expanded attribute could be added dynamically via javascript when the popover region is created. The live examples on this page are generated dynamically, as illustrated in the code snippets below.

Popover markup prior to script

<span class="a11y-popover" data-popover="This is the popover content.">Popover</span>
   

Popover markup after code generation

<span class="a11y-popover-wrap">
    <span class="a11y-popover" data-popover="This is the popover content." id="popover1" aria-expanded="false" role="button" tabindex="0">Popover</span>
    <span id="popover1-reg" aria-labelledby="popover1" role="region">
       This is the popover content.
    </span>
</span>
   

Interaction Pattern

Note that, unlike a tooltip, the popover does not automatically display, the escape key does not dismiss the popover, and the popover is not hidden when the triggering button loses focus. The user must activate the popover trigger to both display and dismiss the popover region.

Example Script

The script used in the live examples in this page is invoked on any element with the class .ally-popover. The script assumes that the popover content will be present in the page or contained in a data-popover attribute on the popover trigger.

If the popover region content is statically present in the page, the html id of the region should set as the value of an aria-controls property on the trigger.

A class is used to designate the position of the popover: .a11y-popover-top, .a11y-popover-right, .a11y-popover-left, .a11y-popover-bottom. This class may be omitted in favor of author-supplied CSS to position the popover regions.

Example CSS

The CSS for the popover region to be displayed must include the desired width for the popover elements. The height will be automatically determined from the popover contents. As the triggering elements are focusable buttons, styling must be used to indicate that they are focusable and when they have received focus. Style the popover trigger buttons so that they are not confused with links in the page.

Here is the CSS used in the page examples:

.a11y-popover-wrap {
   position: relative;
}
a.a11y-popover {
   display: inline-block;
   margin: 1em;
}
.a11y-popover {
   text-decoration: underline wavy #080;
}

.a11y-popover:hover,
.a11y-popover:focus {
   text-decoration-style: wavy;
   outline: 1px solid #080;
   outline-offset: 1px;
}
.a11y-popover-region {
   display: block;
   position: absolute;
   top: -6em;
   left: 1em;
   width: 20em;
   padding: 0.5em 1em;
   background-color: #fff;
   border: 1px solid #222;
   border-radius: 5px;
   box-shadow: 4px 3px 4px rgba(0,0,0,0.25);
   z-index: 100;
}
.a11y-popover-region:after { /* Add downward arrow tool popover */
    position: absolute;
    content: '';
    width: 0;
    height: 0;
}
.a11y-popover-region.a11y-popover-top:after { /* Add downward arrow tool popover */
    left: 8px;
    bottom: -12px;
    border-right: 12px solid transparent;
    border-left: 12px solid transparent;
    border-top: 12px solid #222;
    border-bottom: none;
}
.a11y-popover-region.a11y-popover-bottom:after { /* Add upward arrow tool popover */
    left: 8px;
    top: -12px;
    border-right: 12px solid transparent;
    border-left: 12px solid transparent;
    border-bottom: 12px solid #222;
    border-top: none;
}
.a11y-popover-region.a11y-popover-left:after { /* Add right-facing arrow tool popover */
    right: -12px;
    top: 50%;
    transform: translate(0, -50%);
    border-top: 12px solid transparent;
    border-bottom: 12px solid transparent;
    border-left: 12px solid #222;
    border-right: none;
}
.a11y-popover-region.a11y-popover-right:after { /* Add left-facing arrow tool popover */
    left: -12px;
    top: 50%;
    transform: translate(0, -50%);
    border-top: 12px solid transparent;
    border-bottom: 12px solid transparent;
    border-right: 12px solid #222;
    border-left: none;
}

Downloads