<!– @license Copyright © 2015 The Polymer Project Authors. All rights reserved. This code may only be used under the BSD style license found at polymer.github.io/LICENSE.txt The complete set of authors may be found at polymer.github.io/AUTHORS.txt The complete set of contributors may be found at polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as part of the polymer project is also subject to an additional IP rights grant found at polymer.github.io/PATENTS.txt –>

<link rel=“import” href=“../polymer/polymer.html”> <link rel=“import” href=“../iron-icon/iron-icon.html”> <link rel=“import” href=“../iron-flex-layout/iron-flex-layout.html”> <link rel=“import” href=“../iron-resizable-behavior/iron-resizable-behavior.html”> <link rel=“import” href=“../paper-styles/default-theme.html”> <link rel=“import” href=“../paper-styles/typography.html”>

<!– `<paper-badge>` is a circular text badge that is displayed on the top right corner of an element, representing a status or a notification. It will badge the anchor element specified in the `for` attribute, or, if that doesn't exist, centered to the parent node containing it.

Badges can also contain an icon by adding the `icon` attribute and setting it to the id of the desired icon. Please note that you should still set the `label` attribute in order to keep the element accessible. Also note that you will need to import the `iron-iconset` that includes the icons you want to use. See [iron-icon](../iron-icon) for more information on how to import and use icon sets.

Example:

<div style="display:inline-block">
  <span>Inbox</span>
  <paper-badge label="3"></paper-badge>
</div>

<div>
  <paper-button id="btn">Status</paper-button>
  <paper-badge icon="favorite" for="btn" label="favorite icon"></paper-badge>
</div>

<div>
  <paper-icon-button id="account-box" icon="account-box" alt="account-box"></paper-icon-button>
  <paper-badge icon="social:mood" for="account-box" label="mood icon"></paper-badge>
</div>

### Styling

The following custom properties and mixins are available for styling:

Custom property | Description | Default —————-|————-|———- `–paper-badge-background` | The background color of the badge | `–accent-color` `–paper-badge-opacity` | The opacity of the badge | `1.0` `–paper-badge-text-color` | The color of the badge text | `white` `–paper-badge-width` | The width of the badge circle | `20px` `–paper-badge-height` | The height of the badge circle | `20px` `–paper-badge-margin-left` | Optional spacing added to the left of the badge. | `0px` `–paper-badge-margin-bottom` | Optional spacing added to the bottom of the badge. | `0px` `–paper-badge` | Mixin applied to the badge | `{}`

@group Paper Elements @element paper-badge @demo demo/index.html –>

<dom-module id=“paper-badge”>

<template>
  <style>
    :host {
      display: block;
      position: absolute;
      outline: none;
    }

    :host([hidden]), [hidden] {
      display: none !important;
    }

    iron-icon {
      --iron-icon-width: 12px;
      --iron-icon-height: 12px;
    }

    .badge {
      @apply(--layout);
      @apply(--layout-center-center);
      @apply(--paper-font-common-base);

      font-weight: normal;
      font-size: 11px;
      border-radius: 50%;
      margin-left: var(--paper-badge-margin-left, 0px);
      margin-bottom: var(--paper-badge-margin-bottom, 0px);
      width: var(--paper-badge-width, 20px);
      height: var(--paper-badge-height, 20px);
      background-color: var(--paper-badge-background, --accent-color);
      opacity: var(--paper-badge-opacity, 1.0);
      color: var(--paper-badge-text-color, white);

      @apply(--paper-badge);
    }
  </style>

  <div class="badge">
    <iron-icon hidden$="{{!_computeIsIconBadge(icon)}}" icon="{{icon}}"></iron-icon>
    <span id="badge-text" hidden$="{{_computeIsIconBadge(icon)}}">{{label}}</span>
  </div>
</template>

<script>
  Polymer({
    is: 'paper-badge',

    hostAttributes: {
      role: 'status',
      tabindex: 0
    },

    behaviors: [
      Polymer.IronResizableBehavior
    ],

    listeners: {
      'iron-resize': 'updatePosition'
    },

    properties: {
      /**
       * The id of the element that the badge is anchored to. This element
       * must be a sibling of the badge.
       */
      for: {
        type: String,
        observer: '_forChanged'
      },

      /**
       * The label displayed in the badge. The label is centered, and ideally
       * should have very few characters.
       */
      label: {
        type: String,
        observer: '_labelChanged'
      },

      /**
       * An iron-icon ID. When given, the badge content will use an
       * `<iron-icon>` element displaying the given icon ID rather than the
       * label text. However, the label text will still be used for
       * accessibility purposes.
       */
      icon: {
        type: String,
        value: ''
      }
    },

    attached: function() {
      this._updateTarget();
    },

    attributeChanged: function (name) {
      if (name === 'hidden') {
        this.updatePosition();
      }
    },

    _forChanged: function() {
      // The first time the property is set is before the badge is attached,
      // which means we're not ready to position it yet.
      if (!this.isAttached) {
        return;
      }
      this._updateTarget();
    },

    _labelChanged: function() {
      this.setAttribute('aria-label', this.label);
    },

    _updateTarget: function() {
      this._target = this.target;
      this.async(this.notifyResize, 1);
    },

    _computeIsIconBadge: function(icon) {
      return icon.length > 0;
    },

    /**
     * Returns the target element that this badge is anchored to. It is
     * either the element given by the `for` attribute, or the immediate parent
     * of the badge.
     */
    get target () {
      var parentNode = Polymer.dom(this).parentNode;
      // If the parentNode is a document fragment, then we need to use the host.
      var ownerRoot = Polymer.dom(this).getOwnerRoot();
      var target;

      if (this.for) {
        target = Polymer.dom(ownerRoot).querySelector('#' + this.for);
      } else {
        target = parentNode.nodeType == Node.DOCUMENT_FRAGMENT_NODE ?
            ownerRoot.host : parentNode;
      }

      return target;
    },

    /**
     * Repositions the badge relative to its anchor element. This is called
     * automatically when the badge is attached or an `iron-resize` event is
     * fired (for exmaple if the window has resized, or your target is a
     * custom element that implements IronResizableBehavior).
     *
     * You should call this in all other cases when the achor's position
     * might have changed (for example, if it's visibility has changed, or
     * you've manually done a page re-layout).
     */
    updatePosition: function() {
      if (!this._target)
        return;

      if (!this.offsetParent)
        return;

      var parentRect = this.offsetParent.getBoundingClientRect();
      var targetRect = this._target.getBoundingClientRect();
      var thisRect = this.getBoundingClientRect();

      this.style.left = targetRect.left - parentRect.left +
          (targetRect.width - thisRect.width / 2) + 'px';
      this.style.top = targetRect.top - parentRect.top -
          (thisRect.height / 2) + 'px';
    }
  })
</script>

</dom-module>