Components / Actions

IconButton

An icon-only button with an accessible label, loading state, and three sizes.

Preview

Use cases

Compact row action

Place a named icon action at the end of a list row or toolbar.

Asynchronous action

Use loading while an icon action is in progress to prevent repeated activation.

Usage example

Vue
<script setup lang="ts">
import IconButton from './components/ui/icon-button/IconButton.vue'
</script>

<template>
  <IconButton aria-label="Add item" variant="outline">
    <svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
      <path d="M12 5v14M5 12h14" />
    </svg>
  </IconButton>
</template>

More examples

Close a panel

The label names the action independently of its glyph.

Close a panel
<script setup lang="ts">
import IconButton from './components/ui/icon-button/IconButton.vue'
const emit = defineEmits<{ close: [] }>()
</script>
<template>
  <IconButton label="Close panel" variant="ghost" @click="emit('close')">
    <template #icon><svg aria-hidden="true" viewBox="0 0 24 24"><path d="M5 5l14 14M19 5L5 19" stroke="currentColor" fill="none" /></svg></template>
  </IconButton>
</template>

Busy refresh control

The visual icon gives way to a spinner while refreshing.

Busy refresh control
<script setup lang="ts">
import { ref } from 'vue'
import IconButton from './components/ui/icon-button/IconButton.vue'
const refreshing = ref(false)
async function refresh() {
  refreshing.value = true
  try { await fetch('/api/items') } finally { refreshing.value = false }
}
</script>
<template>
  <IconButton label="Refresh items" :loading="refreshing" @click="refresh">
    <template #icon><svg aria-hidden="true" viewBox="0 0 24 24"><path d="M20 12a8 8 0 1 1-2-5" stroke="currentColor" fill="none" /></svg></template>
  </IconButton>
</template>

Key API

The most useful props, models, slots, events, and methods for this component.

Key API for IconButton
NameTypeDefault or requirement
aria-label / aria-labelledby / labelstringone required
default / #iconicon slotsone required
variantdefault | secondary | outline | ghost | destructivedefault
sizesm | md | lgmd
loadingbooleanfalse
disabledbooleanfalse
typebutton | submit | resetbutton

Name the button with aria-label, aria-labelledby, or the label prop. Put a decorative SVG in the default or #icon slot. Native attributes and click events pass through; loading prevents repeat clicks.

Implementation notes

  • The icon slot is visual decoration; the required label supplies the accessible name.
  • Sizes sm, md, and lg have square 32, 40, and 48 pixel targets.

Accessibility and localization

  • Translate the label prop with the surrounding interface.
  • Keep the slotted SVG aria-hidden and avoid interactive content inside the button.
Weini UIDesign system · Vue component library · Free and public