Gavia UIv1.0.0

Icons

Icons from the built-in SVG catalogue: names, sizes, currentColor and accessible labels.

Name and sizes

Choose a name and compare sizes. SVG uses viewBox 0 0 24 24; currentColor comes from its nearest container.

Selected: folder · 24 px

16 px
20 px
24 px
32 px
48 px

SVG inherits currentColor. Set color on the container or action; pass the pixel size as a number.

Vue SFC · interactive icon selection
<script setup lang="ts">
const name = defineModel<WlIconName>("name", { default: "folder" });
const size = defineModel<number>("size", { default: 24 });
import { WL_ICON_NAMES, WlIcon, type WlIconName, WlSelect } from "gavia-ui";
const comparisonSizes = [16, 20, 24, 32, 48];
function chooseName(value: unknown): void {
  if (typeof value === "string" && (WL_ICON_NAMES as readonly string[]).includes(value)) name.value = value as WlIconName;
}
function chooseSize(value: unknown): void {
  if (typeof value === "number" && comparisonSizes.includes(value)) size.value = value;
}
</script>

<template>
  <section class="icon-playground wl-stack" data-space="lg">
    <div class="wl-grid" data-space="md">
      <div class="wl-stack" data-space="xs">
        <label for="asset-icon-name" class="wl-text-label">{{ "Icon name" }}</label>
        <WlSelect
          id="asset-icon-name"
          :model-value="name"
          :options="[...WL_ICON_NAMES]"
          aria-label="Icon name"
          @update:model-value="chooseName"
        />
      </div>
      <div class="wl-stack" data-space="xs">
        <label for="asset-icon-size" class="wl-text-label">{{ "Icon size" }}</label>
        <WlSelect
          id="asset-icon-size"
          :model-value="size"
          :options="comparisonSizes"
          aria-label="Icon size"
          @update:model-value="chooseSize"
        />
      </div>
    </div>
    <div class="icon-playground-selected wl-inline" data-space="md">
      <span role="img" :aria-label="'Icon ' + name + ', ' + size + ' px'"><WlIcon :name="name" :size="size" /></span>
      <p class="wl-text-body" role="status">{{ "Selected:" }} {{ name }} · {{ size }} px</p>
    </div>
    <div class="icon-playground-comparison" aria-label="Size comparison">
      <figure
        v-for="comparisonSize in comparisonSizes"
        :key="comparisonSize"
        class="icon-playground-sample"
        :data-icon-comparison-size="comparisonSize"
      >
        <WlIcon :name="name" :size="comparisonSize" /><figcaption class="wl-text-small">{{ comparisonSize }} px</figcaption>
      </figure>
    </div>
    <p class="wl-text-small wl-text-muted">{{ "SVG inherits currentColor. Set color on the container or action; pass the pixel size as a number." }}</p>
  </section>
</template>

<style scoped>
.icon-playground { min-width: 0; }
.icon-playground-selected {
  min-height: 80px;
  padding: var(--wl-space-lg);
  background: var(--wl-bg-soft);
  border-radius: var(--wl-corner-control);
  color: var(--wl-text-accent);
}
.icon-playground-selected p { color: var(--wl-text); }
.icon-playground-comparison {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 80px), 1fr));
  gap: var(--wl-space-sm);
}
.icon-playground-sample {
  margin: 0;
  min-width: 0;
  min-height: 110px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--wl-space-md);
  border: 1px solid var(--wl-border);
  border-radius: var(--wl-corner-control);
  color: var(--wl-text);
}
</style>

Icon catalogue

Icons and accessibility

  • WlIcon is decorative by default: its SVG has aria-hidden="true". The visible label of an action or object conveys its meaning.
  • Give a standalone image an accessible name on its role="img" container. If you name the SVG itself, explicitly pass aria-hidden="false".
  • An icon-only button needs an accessible name. WlIconButton accepts aria-label; a text button uses its visible label.

Meaning and action

Materials

Text names the object. The adjacent icon is decorative and hidden from assistive technology.

The container name describes a standalone image.

Materials added: 0. Notifications have not been opened yet.

Vue SFC · application example
<script setup lang="ts">
import { WlButton, WlIcon, WlIconButton } from "gavia-ui";
import { ref } from "vue";
const count = ref(0);
const message = ref("Notifications have not been opened yet.");
</script>

<template>
  <section class="wl-stack" data-space="lg">
    <div class="wl-inline" data-space="sm">
      <WlIcon name="folder" :size="20" /><span class="wl-text-body">{{ "Materials" }}</span>
    </div>
    <p class="wl-text-small wl-text-muted">{{ "Text names the object. The adjacent icon is decorative and hidden from assistive technology." }}</p>
    <div class="wl-inline" data-space="md">
      <span role="img" aria-label="Secure connection"><WlIcon name="shield" :size="24" /></span>
      <p class="wl-text-small">{{ "The container name describes a standalone image." }}</p>
    </div>
    <div class="wl-inline" data-space="sm">
      <WlButton variant="primary" @click="count++">
        <template #icon><WlIcon name="plus" :size="18" /></template>{{ "Add material" }}
      </WlButton>
      <WlIconButton
        icon="bell"
        aria-label="Open notifications"
        @click="message = 'Notifications opened.'"
      />
    </div>
    <p class="wl-text-small" role="status">{{ "Materials added:" }} {{ count }}. {{ message }}</p>
  </section>
</template>

CSS size, aliases and fallback

Size accepts a number in pixels or a CSS string. The resolver accepts a canonical name or alias, including legacy pi-name and pi pi-name. For an unknown name, WlIcon renders its default slot.

Compatible names and fallback icon

CSS size: size="1.25rem".

pi pi-pencil → edit. The application changes the stored value separately.

An unknown name preserves the default slot. You can show a custom fallback symbol.

Vue SFC · application example
<script setup lang="ts">
import { resolveWlIconName, WlIcon } from "gavia-ui";
const legacyName = "pi pi-pencil";
const missingName = "my-missing-icon";
</script>

<template>
  <section class="wl-stack" data-space="lg">
    <div class="wl-inline" data-space="md">
      <WlIcon name="folder" size="1.25rem" />
      <p class="wl-text-small">{{ "CSS size:" }} <code>size="1.25rem"</code>.</p>
    </div>
    <div class="wl-inline" data-space="md">
      <WlIcon :name="legacyName" :size="20" />
      <p class="wl-text-small">
        <code>{{ legacyName }}</code> → <code>{{ resolveWlIconName(legacyName) }}</code>{{
          ". The application changes the stored value separately."
        }}
      </p>
    </div>
    <div class="wl-inline" data-space="md">
      <span role="img" aria-label="Fallback symbol">
        <WlIcon :name="missingName" :size="24"><span class="icon-compatibility-fallback" aria-hidden="true">?</span></WlIcon>
      </span>
      <p class="wl-text-small">{{ "An unknown name preserves the default slot. You can show a custom fallback symbol." }}</p>
    </div>
  </section>
</template>

<style scoped>
.icon-compatibility-fallback {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  border: 1px solid var(--wl-border);
  border-radius: var(--wl-corner-control);
  font: var(--wl-type-label-weight) var(--wl-type-small-size)/1 var(--wl-font);
}
</style>

Adding an SVG

Sources are in packages/ui-kit/icons/<name>.svg. Prepare new icons in the shared style; pnpm icons:sync validates SVG and updates the registry, pnpm icons:check checks that it is up to date.

Check legibility at 16, 20 and 24 px in every theme. The component sets size and colour; SVG files use no external resources or handlers.

Preparing and adding an SVG