# @dreamworld/dw-icon-button

> ## Why don't we use `mwc-icon-button`? - We created `dw-icon` to have extended icon set, sepecific to the app. But, those icons we can't be used with `mwc-icon-button`. - We found issue with `mwc-icon-button` that it can't be resized easily.

Latest version **3.2.11** (published 2026-06-29) · ISC license · 0 weekly downloads

## Install

```sh
npm install @dreamworld/dw-icon-button
pnpm add @dreamworld/dw-icon-button
yarn add @dreamworld/dw-icon-button
bun add @dreamworld/dw-icon-button
```

## Health

**Score 60/100 (C)** — status: active.

Positive: esm support; no vulnerabilities; recently updated; high maintenance score.

Warnings: low downloads; no types.

## Facts

| | |
|---|---|
| Version | 3.2.11 |
| Published | 2026-06-29 |
| First published | 2019-09-05 |
| Weekly downloads | 0 |
| License | ISC |
| TypeScript types | none |
| Module format | ESM + CommonJS |
| Dependencies | 5 |
| Unpacked size | 32.1 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 2 |
| Maintainers | chiragmoradiya, chetang7, ajay-dhameliya, dw-devops |

## Links

- npm: https://www.npmjs.com/package/@dreamworld/dw-icon-button
- Repository: https://github.com/DreamworldSolutions/dw-icon-button
- Homepage: https://github.com/DreamworldSolutions/dw-icon-button#readme
- Issues: https://github.com/DreamworldSolutions/dw-icon-button/issues
- npm.io page: https://npm.io/package/@dreamworld/dw-icon-button

## Dependencies (5)

- [@material/mwc-base](https://npm.io/package/@material/mwc-base.md) 0.27.0
- [@dreamworld/dw-icon](https://npm.io/package/@dreamworld/dw-icon.md) ^4.0.0
- [@dreamworld/web-util](https://npm.io/package/@dreamworld/web-util.md) ^1.2.0
- [@dreamworld/dw-tooltip](https://npm.io/package/@dreamworld/dw-tooltip.md) ^3.1.1
- [@dreamworld/pwa-helpers](https://npm.io/package/@dreamworld/pwa-helpers.md) ^1.13.1

## Recent versions

- 3.2.11 (latest) — 2026-06-29
- 3.2.9-add-background-color-variable.1 (add-background-color-variable) — 2024-12-28
- 3.2.8-ripple-issue.1 (ripple-issue) — 2024-07-23
- 3.2.7-add-tap-highligh-color-css.1 (add-tap-highligh-color-css) — 2024-05-31
- 3.2.6-tip-max-width-in-extra-options.1 (tip-max-width-in-extra-options) — 2024-05-27
- 3.2.5-add-focus-on-button.1 (add-focus-on-button) — 2024-02-09
- 3.2.4-disable-tooltip-issue.1 (disable-tooltip-issue) — 2023-10-25
- 3.2.3-focus-effect-refactor.1 (focus-effect-refactor) — 2023-09-06
- 3.2.1-release-version.1 (release-version) — 2023-03-21
- 3.1.0-update-yarn-lock.1 (update-yarn-lock) — 2023-03-21
- 3.0.1-update-version-of-dw-tooltip.1 (update-version-of-dw-tooltip) — 2023-03-21
- 3.2.0-remove-blur-on-click.1 (remove-blur-on-click) — 2023-03-21
- 3.0.3-ssr.1 (ssr) — 2023-02-14
- 3.1.0-dw-icon-butoon-as-es-module.1 (dw-icon-butoon-as-es-module) — 2023-02-13
- 3.1.0-provide-a-way-to-show-tooltip-when-icon-is-disable.2 (provide-a-way-to-show-tooltip-when-icon-is-disable) — 2023-02-10
- … 100 more at https://npm.io/package/@dreamworld/dw-icon-button/versions

## README

# dw-icon-button

A LitElement-based Web Component that renders a circular icon button with Material Design ripple effects, hover/focus state overlays, tooltip support, and extended icon set via `dw-icon`.

**Why not `mwc-icon-button`?**
- Custom icon sets registered with `dw-icon` cannot be used with `mwc-icon-button`.
- `mwc-icon-button` cannot be resized easily.

---

## 1. User Guide

### Installation & Setup

```bash
yarn add @dreamworld/dw-icon-button
```

```js
import '@dreamworld/dw-icon-button/dw-icon-button.js';
```

The component renders icons using icon font classes. Include the relevant font stylesheets in your HTML:

```html
<!-- Material Icons (filled) -->
<link href="https://fonts.googleapis.com/css?family=Material+Icons&display=block" rel="stylesheet" />

<!-- Material Icons Outlined (for iconFont="OUTLINED") -->
<link href="https://fonts.googleapis.com/css?family=Material+Icons+Outlined&display=block" rel="stylesheet" />

<!-- Material Symbols Outlined (for symbol attribute) -->
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined" rel="stylesheet" />
```

---

### Basic Usage

```html
<!-- Default icon button -->
<dw-icon-button icon="perm_media"></dw-icon-button>

<!-- Disabled -->
<dw-icon-button icon="perm_media" disabled></dw-icon-button>

<!-- Primary color -->
<dw-icon-button icon="perm_media" primary></dw-icon-button>

<!-- Secondary color -->
<dw-icon-button icon="perm_media" secondary></dw-icon-button>
```

---

### API Reference

#### Properties

| Property | Attribute | Type | Default | Reflected | Description |
|---|---|---|---|---|---|
| `icon` | `icon` | `String` | — | No | Name of the icon to render via `dw-icon` |
| `disabled` | `disabled` | `Boolean` | `false` | Yes | Disables the button. Sets `tabindex="-1"` and stops click event propagation |
| `iconSize` | `icon-size` | `Number` | `undefined` | No | Icon size in pixels. When unset, `dw-icon` uses its own default (24px) |
| `buttonSize` | `button-size` | `Number` | `undefined` | No | Explicit button width/height in pixels. Padding is computed as `(buttonSize - iconSize) / 2`. When unset, the button fills its parent |
| `primary` | `primary` | `Boolean` | `false` | Yes | Renders the icon and ripple using `--mdc-theme-primary` |
| `secondary` | `secondary` | `Boolean` | `false` | Yes | Renders the icon and ripple using `--mdc-theme-secondary` |
| `title` | `title` | `String` | — | No | Tooltip text. Shown on `mouseenter` when the button is **not** disabled and **not** on a touch device |
| `disabledTitle` | `disabled-title` | `String` | — | No | Tooltip text. Shown on `mouseenter` only when `disabled` is `true` |
| `tipExtraOptions` | — | `Object` | `{}` | No | Additional options object merged into `dw-tooltip`'s `extraOptions` for the `title` tooltip |
| `tipOffset` | — | `Array` | `[0, 8]` | No | Displacement of the tooltip from the button as `[skidding, distance]`. Applied to both the `title` and `disabledTitle` tooltips |
| `iconFont` | `icon-font` | `String` | — | Yes | Icon font variant. Accepted values: `FILLED`, `OUTLINED` |
| `symbol` | `symbol` | `Boolean` | `false` | Yes | When `true`, renders using the Material Symbols font instead of Material Icons |
| `placement` | `placement` | `String` | `'top'` | No | Tooltip position relative to the button. Accepts: `top`, `bottom`, `left`, `right`, with optional `-start` or `-end` suffix (e.g. `top-start`, `left-end`) |

> **Tooltip note:** `title` and `disabledTitle` are independent. Set both to show a tooltip in both enabled and disabled states.

#### Methods

| Method | Signature | Description |
|---|---|---|
| `focus` | `focus(): void` | Programmatically focuses the internal `<button>` element |

#### Events

No custom events are dispatched by this component. Standard DOM events (`click`, `mousedown`, `mouseup`, etc.) propagate from the host element normally, **except** when `disabled` is `true` — in that case, `click` events on the internal wrapper are stopped via `stopImmediatePropagation`.

#### Slots

Not supported. The component renders `dw-icon` internally within shadow DOM. Light DOM (`slot`) content is not accepted.

---

### CSS Custom Properties

| Property | Default | Description |
|---|---|---|
| `--dw-icon-color` | (from `dw-icon`) | Icon color in the default state |
| `--dw-icon-color-active` | `rgba(0, 0, 0, 0.87)` | Icon color when the button is focused |
| `--dw-icon-color-disabled` | (from `dw-icon`) | Icon color when `disabled` is `true` |
| `--dw-icon-button-background` | `transparent` | Background color of the button element |
| `--dw-icon-button-padding` | `12px` | Button padding. Automatically overridden when `buttonSize` is set |
| `--mdc-theme-primary` | — | Applied to icon color and ripple when `primary` attribute is set |
| `--mdc-theme-secondary` | — | Applied to icon color and ripple when `secondary` attribute is set |
| `--mdc-theme-on-surface` | — | Color used for hover/focus state overlays and ripple |

```css
/* Example: custom-colored icon button */
dw-icon-button {
  --dw-icon-color: #6200ee;
  --dw-icon-color-active: #3700b3;
  --dw-icon-button-background: #f5f5f5;
}
```

---

### Sizing

To size the button container using CSS (without the `buttonSize` property), set `width` and `height` directly on the element:

```css
dw-icon-button {
  width: 48px;
  height: 48px;
}
```

To use `buttonSize` for self-contained sizing with automatic padding:

```html
<!-- 48px button with 24px icon → padding = (48 - 24) / 2 = 12px -->
<dw-icon-button icon="more_vert" buttonSize="48" iconSize="24"></dw-icon-button>
```

---

### Advanced Usage

#### Tooltip on enabled button

```html
<dw-icon-button
  icon="more_vert"
  .title=${"More options"}
  .placement=${"bottom"}
></dw-icon-button>
```

#### Tooltip on disabled button

```html
<dw-icon-button
  icon="more_vert"
  disabled
  .disabledTitle=${"This action is unavailable"}
  .placement=${"bottom"}
></dw-icon-button>
```

#### Tooltip in both states

```html
<dw-icon-button
  icon="more_vert"
  .title=${"More options"}
  .disabledTitle=${"This action is unavailable"}
  .placement=${"top"}
></dw-icon-button>
```

#### Custom tooltip delay via `tipExtraOptions`

```html
<dw-icon-button
  icon="info"
  .title=${"Help"}
  .tipExtraOptions=${{ delay: [200, 0] }}
></dw-icon-button>
```

#### Custom tooltip offset via `tipOffset`

```html
<dw-icon-button
  icon="info"
  .title=${"Help"}
  .tipOffset=${[0, 12]}
></dw-icon-button>
```

#### Material Symbols (outlined)

```html
<dw-icon-button
  icon="signal_wifi_statusbar_not_connected"
  iconFont="OUTLINED"
  symbol
  iconSize="48"
></dw-icon-button>
```

#### Custom SVG icons (registered via `DwIcon.addIcons`)

```js
import { DwIcon } from '@dreamworld/dw-icon/dw-icon.js';
import { svg } from 'lit';

DwIcon.addIcons({
  my_custom_icon: svg`<svg viewBox="0 0 24 24">...</svg>`,
});
```

```html
<dw-icon-button icon="my_custom_icon"></dw-icon-button>
```

#### Programmatic focus

```js
const btn = document.querySelector('dw-icon-button');
btn.focus();
```

---

## 2. Developer Guide / Architecture

### Architecture Overview

| Concern | Implementation |
|---|---|
| Base class | `DwIconButton extends buttonFocus(LitElement)` |
| Composition pattern | Mixin (`buttonFocus` from `@dreamworld/pwa-helpers`) layered over `LitElement` |
| DOM model | Shadow DOM only; no light DOM slots |
| Icon rendering | Delegates to `<dw-icon>` inside shadow DOM |
| Tooltip rendering | Conditionally renders `<dw-tooltip>` in shadow DOM; two independent instances managed for `title` and `disabledTitle` |

### Ripple State Machine

The ripple effect is driven entirely by CSS class toggling:

1. **Entry** (`mousedown` / `touchstart`): `requestAnimationFrame` adds `ripple-entry` class → CSS applies `scale-in-ripple` (225ms) and `fade-in-ripple` (75ms) keyframe animations on `::after`.
2. A `Promise` (`waitForEntryAnimation`) resolves after 225ms, ensuring exit does not begin before entry completes.
3. **Exit** (`mouseup` / `mouseleave` / `touchend`): Awaits `waitForEntryAnimation`, then adds `ripple-exit` → CSS applies `fade-out-ripple` (250ms). After 250ms, both classes are removed.

### Touch Device Handling

`isTouchDevice()` (from `@dreamworld/web-util`) is called:
- In the **constructor** to set `_touchDevice` property (reflected as `touch-device` attribute).
- In **`render()`** to suppress the `title` tooltip on touch devices.

The `touch-device` attribute disables hover overlays via the CSS rule:
```css
:host(:not([disabled]):not([touch-device])) button:hover::before { opacity: 0.04; }
```

### Focus Effect Suppression

To distinguish keyboard focus from pointer/touch focus:
- `pointerdown` sets `_noFocusEffect = true` → adds `no-focus-effect` attribute.
- `blur` resets `_noFocusEffect = false` → removes the attribute.

The attribute disables the focus overlay:
```css
:host([no-focus-effect]) button:focus::before { opacity: 0; }
```

This ensures the focus ring only appears for keyboard navigation, not after mouse or touch interaction.

### Disabled Click Interception

When `disabled` is `true`, the internal `_onTooltipContainerClick` handler on the wrapper `<div>` calls `e.stopImmediatePropagation()`. This prevents click events from reaching parent elements even though the underlying `<button>` has `tabindex="-1"` (not `disabled` attribute), which is necessary to allow the `disabledTitle` tooltip to still receive pointer events.

### Module Entry Point

The package exports a single ES module:

```
main: "dw-icon-button.js"
type: "module"
```

The custom element `dw-icon-button` is registered via `customElements.define` at the end of `dw-icon-button.js`.

---
_Source: https://npm.io/package/@dreamworld/dw-icon-button · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
