Skip to content

cspanring/ember-tooltips

 
 

Repository files navigation

Ember-tooltips (and popovers) Build Status npm Ember Observer Score

Render tooltips and popovers on components and other HTML elements using HTMLBars.

Installation

ember install ember-tooltips

Documentation

Documentation for usage is below:

Usage

Ember Tooltip

The easiest way to add a tooltip to any element is with the {{ember-tooltip}} component:

{{#my-component}}
  Hover for more info

  {{ember-tooltip text='Here is more info!'}}
{{/my-component}}

Or in block form:

{{#my-component}}
  Hover for more info

  {{#tooltip}}
    Here is the info in a tooltip!
  {{/ember-tooltip}}
{{/my-component}}

The tooltip will always be rendered on its parent element unless you specify the targetId attribute:

{{input id='has-info-tooltip'}}

{{#ember-tooltip targetId='has-info-tooltip'}}
  Here is some more info
{{/ember-tooltip}}

Tooltips and popovers are lazy rendered. That means the are only rendered in the DOM once the user interacts with the target element.

Options can be set on the {{ember-tooltip}} as attributes:

{{#my-component}}
  Click for more info

  {{#ember-tooltip event='click'}}
    This info will show on click!
  {{/ember-tooltip}}
{{/my-component}}

Documentation for supported options is located here.

Ember popover

Popovers can be created with the {{ember-popover}} component, which is added to apps just like {{ember-tooltip}}.

Popovers support the same target behavior as tooltips; popovers will render on their parent element unless a targetId is supplied.

All the options passed to tooltip components can be passed to popover components:

{{#my-component}}
  Click for more info

  {{#ember-popover event='click'}}
    This info will show in a popover on click!
  {{/ember-popover}}
{{/my-component}}

Popovers also benefit from a hide API made publically acessible:

{{#ember-popover as |popover|}}
  Click <a href {{action 'hide' target=popover}}>here</a> to hide the popover
{{/ember-popover}}

In addition, a popoverHideDelay option is made available for popovers only.

Targets

The concept of a 'target' is used through this addon. A target is the element that the tooltip or popover is attached to. Each tooltip or popvers has its own target. Interacting with this target will render and/or show the tooltip or popover.

For example, if you want to show a tooltip over a button when the user hovers over the button, the button is the target. If you want to show a popover over an input when the user focuses on the input, the input is the target.

Options

Options are set as attributes on the tooltip/popover components. Current tooltip/popover properties this addon supports are:

Class

Type String
Default none

Adds a class to any tooltip:

{{ember-tooltip class='tooltip-warning'}}

Delay

Type Number
Default 0

Delays showing the tooltip by the given number of milliseconds.

{{!--Delays the show animation by 500ms--}}

{{ember-tooltip delay=500}}

This does not affect the hiding of the tooltip. See also, delayOnChange.

Delay on change

Type Boolean
Default true

Whether or not to enforce the delay even when the user transitions their cursor between multiple target elements with tooltips.

See this animation for a visual explanation:

{{!--Forces delay to be enforced when the user skips
between elements with tooltips--}}

{{ember-tooltip delayOnChange=true}}

Duration

Type Number
Default 0

Sets the duration for which the tooltip will be open, in milliseconds. When the tooltip has been opened for the duration set it will hide itself.

The user will still hide the tooltip if the hide event occurs before the duration expires.

{{!-- Closes the tooltip after 1000ms--}}

{{ember-tooltip duration=1000}}

Leave as 0 if you wish for the tooltip to remain open indefinitely.

Effect

Type String
Default 'slide'

Sets the animation used to show and hide the tooltip. Possible options are:

  • 'fade'
  • 'slide'
  • 'none'
{{ember-tooltip effect='slide'}}

Event

Type String
Default 'hover'

The event that the tooltip will hide and show for. Possible options are:

  • 'hover'
  • 'click'
  • 'focus' (hides on blur)
  • 'none'
{{ember-tooltip event='click'}}

This event is overwritten by the individual hideOn and showOn properties. In effect, setting event sets hideOn and shownOn for you.

The tooltip can also be shown programatically by passing in the isShown property, documented here.

Hide on

Type String
Default 'none'

Sets the event that the tooltip will hide on. This overwrites any event set with the event option.

This can be any javascript-emitted event.

{{!--This tooltip will hide on mouseleave, NOT click--}}

{{ember-tooltip
  event='click'
  hideOn='mouseleave'
}}

Usually, you'll use the event option, which sets showOn and hideOn automatically, instead of this option.

This opeion does not affect the event the tooltip shows on. That is set by the showOn option. This will override the event property in deciding when the tooltip is hidden.

Side

Type String
Default 'top'

Sets the side the tooltip will render on. If keepInWindow is set to true, side can be overwritten to keep the tooltip on screen.

Possible options are:

  • 'top'
  • 'right'
  • 'bottom'
  • 'left'
{{!--The tooltip will render on the right of the target element--}}

{{ember-tooltip
  side='right'
}}

Show on

Type String
Default 'none'

Sets the event that the tooltip will show on. This overwrites any event set with the event option.

This can be any javascript-emitted event.

{{!--This tooltip will show on click, NOT hover--}}

{{ember-tooltip
  showOn='click'
}}

Usually, you'll use the event option, which sets showOn and hideOn automatically, instead of this option.

This opeion does not affect the event the tooltip hides on. That is set by the hideOn option. This will override the event property in deciding when the tooltip is shown.

Spacing

Type Number
Default 10

Sets the number of pixels the tooltip will render from the target element. A higher number will move the tooltip further from the target. This can be any number.

{{!--Render the tooltip 20px from the target element--}}
{{ember-tooltip spacing=20}}

Text

Type String
Default null

Sets the text of any tooltip without needing the tooltip to be written in block form.

{{#my-component}}
  Hover for more info

  {{ember-tooltip text='Here is more info!'}}
{{/my-component}}

Is Shown

Type Boolean
Default false

Gives you a programatic way to hide and show a tooltip. Set this value to true to manually show the tooltip.

This can be useful alongside event='none' when you only want to toolip to show when you specific and not based on an user action.

{{!--Binds the tooltip visibility to the showTooltip property--}}
{{ember-tooltip isShown=true event='none'}}

Hide delay

Type Number
Default 250

POPOVER ONLY: The number of milliseconds before the popover will hide after the user hovers away from the popover and the popover target. This is only applicable when event='hover'.

{{ember-popover event='hover' hideDelay=300}}

popover-hover

Setting Defaults

You can set the default for any option by extending the {{ember-tooltip}} or {{ember-popover}} component:

{{!--your-app/components/ember-tooltip}}--}}

import EmberTooltipComponent from 'ember-tooltips/components/ember-tooltip';

export default EmberTooltipComponent.extend({
  effect: 'fade',
  side: 'bottom',
});

Actions

Four actions are available for you to hook onto through the tooltip/popover lifecycle:

{{ember-tooltip
  onDestroy='onDestroy'
  onHide='onHide'
  onRender='onRender'
  onShow='onShow'
}}

Testing

Test helpers

This addon exposes testing helpers which can be used inside of the consuming app's acceptance and integration tests. We use a tooltip-centric naming convention but these can also be used to test popovers.

Publically available test helpers are:

All assert helpers require assert to be passed as the first param and some accept a second, optional param for additional test options. For detailed usage instructions and examples, see the documentation for each test helper below.

All test helpers can be imported from the following path:

'appname/tests/helpers/ember-tooltips';

For example:

// appname/tests/integration/components/some-component.js

import {
  assertTooltipRendered,
} from 'appname/tests/helpers/ember-tooltips';
import { moduleForComponent, test } from 'ember-qunit';

moduleForComponent('some-component', 'Integration | Component | Some', {
  integration: true,
});

test('ember-tooltip animates with a delay', function(assert) {

  // ... Test content...

  assertTooltipRendered(assert);

  // ... More test content...

});

assertTooltipContent()

Asserts that a tooltip or popover has content that matches a given string.

import {
  afterTooltipRenderChange,
  assertTooltipContent,
} from 'appname/tests/helpers/ember-tooltips';

test('Example test', function(assert) {

  this.render(hbs`{{ember-tooltip text='More info' isShown='true'}}`);

  afterTooltipRenderChange(assert, () => {
    assertTooltipContent(assert, {
      contentString: 'More info',
    });
  });
});

The options hash accepts:

assertTooltipRendered()

Asserts that a tooltip or popover has been rendered in the DOM.

import {
  afterTooltipRenderChange,
  assertTooltipRendered,
  triggerTooltipTargetEvent,
} from 'appname/tests/helpers/ember-tooltips';

test('Example test', function(assert) {

  this.render(hbs`{{ember-tooltip}}`);

  triggerTooltipTargetEvent(this.$(), 'mouseenter');

  afterTooltipRenderChange(assert, () => {
    assertTooltipRendered(assert);
  });
});

Please note, assertTooltipRendered() does not assert that the tooltip or popover is visible to the user - use assertTooltipVisible() for that.

Given this addon's lazy rendering capabilities (explained in Targets), tooltips will not be rendered until the target is interacted with. As such, this helper is often used in conjunction with triggerTooltipTargetEvent() or isShown='true' to test a tooltip property after the tooltip is rendered.

For example:

import {
  afterTooltipRenderChange,
  assertTooltipRendered,
  triggerTooltipTargetEvent,
} from 'appname/tests/helpers/ember-tooltips';

test('Example test', function(assert) {

  this.render(hbs`
    {{ember-tooltip text='Hello'}}
  `);

  /* Tooltip won't be rendered in the DOM yet because lazy rendering delays the rendering until the user interacts with the target */

  triggerTooltipTargetEvent(this.$(), 'mouseenter');

  /* Now the user has interacted with the target, so the tooltip should be rendered... */

  afterTooltipRenderChange(assert, () => {
    assertTooltipRendered(assert);
  });
});

The options hash accepts:

assertTooltipNotRendered()

Asserts that a tooltip or popover has not been rendered in the DOM.

Why is this test helper useful? Well, given this addon's lazy rendering capabilities (explained in Targets), tooltips may not be rendered until the target is interacted with.

import {
  afterTooltipRenderChange,
  assertTooltipNotRendered,
  assertTooltipRendered,
  triggerTooltipTargetEvent,
} from 'appname/tests/helpers/ember-tooltips';

test('Example test', function(assert) {

  this.render(hbs`{{ember-tooltip}}`);

  afterTooltipRenderChange(assert, () => {
    assertTooltipNotRendered(assert);

    triggerTooltipTargetEvent(this.$(), 'mouseenter');

    afterTooltipRenderChange(assert, () => {
      assertTooltipRendered(assert);
    });
  });
});

This helper does not assert that the tooltip or popover is not visible to the user. The assertion will fail if the tooltip or popover is not visible to the user but is still rendered in the DOM. If you want to assert that a tooltip or popover is not visible once it's rendered in the DOM, use assertTooltipNotVisible().

The options hash accepts:

assertTooltipVisible()

Asserts that a tooltip or popover is visible.

This helper is usually used in conjunction with triggerTooltipTargetEvent() to assert that a particular user interaction shows a tooltip to the user.

For example:

import {
  afterTooltipRenderChange,
  assertTooltipVisible,
  triggerTooltipTargetEvent,
} from 'appname/tests/helpers/ember-tooltips';

test('Example test', function(assert) {

  this.render(hbs`{{ember-tooltip}}`);

  triggerTooltipTargetEvent(this.$(), 'mouseenter');

  /* Asserts that the tooltip is shown when the user hovers over the target, which is this test's element */

  afterTooltipRenderChange(assert, () => {
    assertTooltipVisible(assert);
  });
});

You may use this helper with a variety of different user interactions. Here's an example that asserts that a tooltip is shown when the user focusses on an input:

import {
  afterTooltipRenderChange,
  assertTooltipVisible,
  triggerTooltipTargetEvent,
} from 'appname/tests/helpers/ember-tooltips';

test('Example test', function(assert) {

  this.render(hbs`
    <input id="url-input">
    {{ember-tooltip targetId='url-input'}}
  `);

  triggerTooltipTargetEvent($('#url-input'), 'focus');

  /* Asserts that the tooltip is made visible when the user focuses on the input */

  afterTooltipRenderChange(assert, () => {
    assertTooltipVisible(assert);
  });
});

This does not assert that the tooltip or popover is rendered in the DOM (regardless of visibility to the user) - use assertTooltipRendered() for that.

The options hash accepts:

assertTooltipNotVisible()

Asserts that a tooltip or popover is not visible.

This helper is usually used in conjunction with triggerTooltipTargetEvent() to assert that a particular user interaction hides a tooltip to the user.

For example:

import {
  afterTooltipRenderChange,
  assertTooltipNotVisible,
  assertTooltipVisible,
  triggerTooltipTargetEvent,
} from 'appname/tests/helpers/ember-tooltips';

test('Example test', function(assert) {

  this.render(hbs`{{ember-tooltip}}`);

  /* Hover over the target to show the tooltip... */

  triggerTooltipTargetEvent(this.$(), 'mouseenter');

  afterTooltipRenderChange(assert, () => {
    assertTooltipVisible(assert);

    /* Stop hovering over the target in order to hide the tooltip... */

    triggerTooltipTargetEvent(this.$(), 'mouseleave');

    afterTooltipRenderChange(assert, () => {
      assertTooltipNotVisible(assert);
    });
  });
});

The options hash accepts:

assertTooltipSide()

Asserts that a tooltip or popover is rendered on the correct side of the target.

This helper tests the side option that can be passed to tooltips and popovers.

An options hash is required and it must contain a side property. For example:

import {
  afterTooltipRenderChange,
  assertTooltipSide,
} from 'appname/tests/helpers/ember-tooltips';

test('Example test', function(assert) {

  this.render(hbs`
    {{ember-tooltip side='right' isShown=true}}
  `);

  /* Asserts that the tooltip is rendered but not shown when the user hovers over the target, which is this test's element */

  afterTooltipRenderChange(assert, () => {
    assertTooltipSide(assert, {
      side: 'right', // SIDE IS REQUIRED
    });
  });

});

The options hash accepts:

assertTooltipSpacing()

Asserts that a tooltip or popover is rendered a given number of pixels from the target.

This helper tests the spacing option that can be passed to tooltips and popovers.

An options hash is required and it must contain spacing and side properties. For example:

import {
  afterTooltipRenderChange,
  assertTooltipSpacing,
  triggerTooltipTargetEvent,
} from 'appname/tests/helpers/ember-tooltips';

test('Example test', function(assert) {

  this.render(hbs`
    {{ember-tooltip spacing=35 isShown=true}}
  `);

  triggerTooltipTargetEvent(this.$(), 'mouseenter');

  /* Asserts that the tooltip is rendered but not shown when the user hovers over the target, which is this test's element */

  afterTooltipRenderChange(assert, () => {
    assertTooltipSide(assert, {
      side: 'right', // SIDE IS REQUIRED
      spacing: 35, // SPACING IS REQUIRED
    });
  });
});

The options hash accepts:

triggerTooltipTargetEvent()

Triggers an event on a tooltip or popover's target.

This helper does not require assert to be passed. Instead, it requires a jQuery element and event name:

import {
  triggerTooltipTargetEvent,
} from 'appname/tests/helpers/ember-tooltips';

test('Example test', function(assert) {

  this.render(hbs`{{ember-tooltip}}`);

  triggerTooltipTargetEvent(this.$(), 'mouseenter');

});

Other events can be passed for more complex interactions:

import {
  triggerTooltipTargetEvent,
} from 'appname/tests/helpers/ember-tooltips';

test('Example test', function(assert) {

  this.render(hbs`
    {{input id='has-info-tooltip'}}

    {{#ember-tooltip targetId='has-info-tooltip' event='focus'}}
      Here is some more info
    {{/ember-tooltip}}
  `);

  triggerTooltipTargetEvent($('#has-info-tooltip'), 'focus');

  /* Then we'd do something like assert that the tooltip has been rendered... */

});

Allowed event names are:

  • 'mouseenter'
  • 'mouseleave'
  • 'click'
  • 'focus'
  • 'focusin'
  • 'blur'

The options hash accepts:

Test helper options

Most test helpers accept a second, optional param called options. This is an object you can pass that customizes various options in a test. The properties you can pass via options for each test helper is listed above. Below you will find more information for each property.

Test helper option: contentString

The content string you expect the tooltip or popover to have.

Type String
Default null

Usage example:

import { assertTooltipRendered } from 'appname/tests/helpers/ember-tooltips';

test('Example test', function(assert) {

  this.render(hbs`{{ember-tooltip test='More info'}}`);

  assertTooltipContent(assert, {
    contentString: 'More info',
  });

});

Test helper option: selector

The selector of the tooltip or popover you are testing.

If more than one tooltip or popover is found in the DOM when you run an assertion, you will be asked to specify this.

Type String
Default '.ember-tooltip, .ember-popover'

Usage example:

import { assertTooltipRendered } from 'appname/tests/helpers/ember-tooltips';

test('Example test', function(assert) {

  this.render(hbs`
    {{ember-tooltip class='test-tooltip'}}
    {{ember-tooltip}}
  `);

  assertTooltipRendered(assert, {
    selector: '.test-tooltip',
  });
});

Test helper option: targetSelector

The selector of the tooltip or popover target you are testing. See Targets for an explanation on what a 'target' is.

If more than one tooltip or popover target is found in the DOM when you run an assertion, you will be asked to specify this.

Type String
Default '.ember-tooltip-or-popover-target'

Usage example:

import { assertTooltipSpacing } from 'appname/tests/helpers/ember-tooltips';

test('Example test', function(assert) {

  this.render(hbs`
    <div class="test-target">
      {{ember-tooltip}}
    </div>

    <div>
      {{ember-tooltip}}
    </div>
  `);

  assertTooltipSpacing(assert, {
    targetSelector: '.test-target',
  });
});

Test helper option: side

The value for the tooltip or popover's side option that you are asserting.

Type String
Default `null

For example, if you specify for the tooltip or popover be shown on the right of the target using side='right', you will pass side: 'right' in assertions that test side. Here is the code for this example:

import { assertTooltipSide } from 'appname/tests/helpers/ember-tooltips';

test('Example test', function(assert) {

  this.render(hbs`
    {{ember-tooltip side='right'}}
  `);

  assertTooltipSide(assert, {
    side: 'right',
  });
});

Test helper option: spacing

The value for the tooltip or popover's spacing option that you are asserting. Specify as a number of pixels expected (without a px unit).

Type Number
Default null

For example, if you specify for the tooltip or popover be shown on the right of the target using side='right', you will pass side: 'right' in assertions that test side. Here is the code for this example:

import { assertTooltipSide } from 'appname/tests/helpers/ember-tooltips';

test('Example test', function(assert) {

  this.render(hbs`
    {{ember-tooltip spacing='35'}}
  `);

  assertTooltipSpacing(assert, {
    spacing: 35,
  });
});

Test helper option: event

The name of the event that you would like to trigger on an element.

Type String
Default null

Usually used to specify an event for showing/hiding tooltips and popovers:

import {
  triggerTooltipTargetEvent
} from 'appname/tests/helpers/ember-tooltips';

test('Example test', function(assert) {

  this.render(hbs`
    {{ember-tooltip event='click'}}
  `);

  triggerTooltipTargetEvent(assert, {
    event: 'click',
  });

  /* Now the tooltip should be visible! */

});

Accessibility

This addon aims to meet 508 compliance.

Elements with tooltips are given a tabindex attribute and when the element receives focus, the tooltip with show.

Additionally, the aria-describedby, title, id, and role attributes are managed by this addon.

There is always room for improvement and PRs to improve accessibility are welcome.

Development

All PRs and issues are welcome.

  • git clone https://github.com/sir-dunxalot/ember-tooltips.git
  • cd ember-tooltips
  • npm install && bower install
  • ember s
  • ember test, ember try:testall, or the /tests route

Please include tests and documentation updates with any new features.

You do not need to bump the version when you have a PR.

To release an update to the demo app:

git checkout master # make sure you're on master branch
ember github-pages:commit --message "Some commit message" # Builds the app
git push origin gh-pages:gh-pages # Deploys the app

About

Easy and extendible tooltips for Ember components - http://sir-dunxalot.github.io/ember-tooltips/

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • JavaScript 84.8%
  • CSS 7.9%
  • HTML 7.3%