---
title: "Icon"
description: "Decorative and linked icons with optional background."
requested_language: hu
language: en
translation_notice: "This page isn't translated yet"
url: https://docs.systhema.app/hu/components/icon
version: unreleased (main)
docs_index: https://docs.systhema.app/hu/llms.txt
---
> This page isn't translated yet. Showing English.


`Icon` sizes and colors an icon from the `icon` tokens, with an optional filled background. It wraps whatever you put inside, an inline SVG, an `<img>` or a glyph, and `Icon.a` turns it into a link with a hover state.

```tsx preview title="Icon"
import { Icon } from '@systhemaui/next'

export default function Demo() {
  return (
    <div className="flex flex-wrap items-center gap-6">
      <Icon aria-hidden="true">
        <svg viewBox="0 -960 960 960" fill="currentColor" focusable="false">
          <path d="m422-232 207-248H469l29-227-185 267h139l-30 208ZM320-80l40-280H160l360-520h80l-40 320h240L400-80h-80Z" />
        </svg>
      </Icon>
      <Icon hasBackground aria-hidden="true">
        <svg viewBox="0 -960 960 960" fill="currentColor" focusable="false">
          <path d="m422-232 207-248H469l29-227-185 267h139l-30 208ZM320-80l40-280H160l360-520h80l-40 320h240L400-80h-80Z" />
        </svg>
      </Icon>
    </div>
  )
}
```

## Import

```tsx
import { Icon } from '@systhemaui/next'
```

In a React app without Next.js, import it from `@systhemaui/react`. There `Icon.a` renders a plain anchor.

## Variants and tags

`Icon` renders a `<span>` by default. It has one shorthand, `Icon.a`, which renders a link (the same shape as `Button.a`, `Chip.a` and `MediaWrapper.a`). Use `as` for any other element, for example `as="div"` or `as="svg"`.

`hasBackground` adds the `icon-has-background` class: a filled, bordered tile sized by `--icon-has-background-size`, with the icon inside at `--icon-has-background-icon-size`.

```tsx preview title="Plain, with background, linked"
import { Icon } from '@systhemaui/next'

const mail =
  'M160-160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h640q33 0 56.5 23.5T880-720v480q0 33-23.5 56.5T800-160H160Zm320-280L160-640v400h640v-400L480-440Zm0-80 320-200H160l320 200Z'

export default function Demo() {
  return (
    <div className="flex flex-wrap items-center gap-6">
      <Icon aria-hidden="true">
        <svg viewBox="0 -960 960 960" fill="currentColor" focusable="false">
          <path d={mail} />
        </svg>
      </Icon>
      <Icon hasBackground aria-hidden="true">
        <svg viewBox="0 -960 960 960" fill="currentColor" focusable="false">
          <path d={mail} />
        </svg>
      </Icon>
      <Icon.a href="#variants-and-tags" aria-label="Email us">
        <svg viewBox="0 -960 960 960" fill="currentColor" aria-hidden="true" focusable="false">
          <path d={mail} />
        </svg>
      </Icon.a>
      <Icon.a href="#variants-and-tags" hasBackground aria-label="Email us">
        <svg viewBox="0 -960 960 960" fill="currentColor" aria-hidden="true" focusable="false">
          <path d={mail} />
        </svg>
      </Icon.a>
    </div>
  )
}
```

Hover the two linked icons: as an `<a>`, an icon takes the hover colors from the `colorSystem.icon.hover.*` tokens. Icons that are not links keep a flat look.

> [!NOTE]
> Changed in v1.6.0: the `Icon.span`, `Icon.div` and `Icon.svg` shorthands were removed. Write `<Icon as="span">`, `<Icon as="div">` or `<Icon as="svg">`; `systhema upgrade` runs the `rewrite-icon-tag-variants` codemod for you. See the [v1.6.0 release notes](../release-notes/v1.6.0.md).

## Examples

### The SVG as the icon

With `as="svg"` the icon element is the SVG itself, which saves a wrapper.

```tsx preview title="SVG as the icon"
import { Icon } from '@systhemaui/next'

export default function Demo() {
  return (
    <div className="flex items-center gap-6">
      <Icon as="svg" viewBox="0 -960 960 960" fill="currentColor" aria-hidden="true" focusable="false">
        <path d="m233-120 65-281L80-590l288-25 112-265 112 265 288 25-218 189 65 281-247-149-247 149Z" />
      </Icon>
    </div>
  )
}
```

### An image as the icon

Children are sized to fill the icon with `object-fit: contain`, so a raster or SVG file works as well as inline markup.

```tsx preview title="Image icon"
import { Icon } from '@systhemaui/next'

export default function Demo() {
  return (
    <div className="flex items-center gap-6">
      <Icon>
        <img src="/demo-assets/logo-mark.svg" alt="Northwind" />
      </Icon>
      <Icon hasBackground>
        <img src="/demo-assets/logo-mark.svg" alt="Northwind" />
      </Icon>
    </div>
  )
}
```

### SVG markup from the CMS

The Icon block stores an icon as an SVG string. Render it with `dangerouslySetInnerHTML`, and only for markup you trust.

```tsx
import { Icon } from '@systhemaui/next'

export function CmsIcon({ svg }: { svg: string }) {
  return <Icon hasBackground aria-hidden="true" dangerouslySetInnerHTML={{ __html: svg }} />
}
```

### Overriding size and color

Every icon rule is wrapped in `:where()`, so it has no specificity and any utility class wins without `!`.

```tsx preview title="Utility overrides"
import { Icon } from '@systhemaui/next'

const bolt =
  'm422-232 207-248H469l29-227-185 267h139l-30 208ZM320-80l40-280H160l360-520h80l-40 320h240L400-80h-80Z'

export default function Demo() {
  return (
    <div className="flex items-center gap-6">
      <Icon className="size-6" aria-hidden="true">
        <svg viewBox="0 -960 960 960" fill="currentColor" focusable="false">
          <path d={bolt} />
        </svg>
      </Icon>
      <Icon className="size-12 text-amber-500" aria-hidden="true">
        <svg viewBox="0 -960 960 960" fill="currentColor" focusable="false">
          <path d={bolt} />
        </svg>
      </Icon>
    </div>
  )
}
```

## Props

`Icon` takes the props of the element it renders. `Icon.a` takes link props.

<!-- generated:props @systhemaui/react IconProps -->

| Prop                         | Type          | Default  | Description |
| ---------------------------- | ------------- | -------- | ----------- |
| `as`                         | `ElementType` | `'span'` |             |
| `className`                  | `string`      | -        |             |
| `hasBackground`              | `boolean`     | `false`  |             |
| `children`                   | `ReactNode`   | -        |             |
| …and all `<span>` attributes |               |          |             |

<!-- /generated -->

## HTML and CSS

Without React, add `icon` (and `icon-has-background`) to any element around the SVG:

```html
<span class="icon" aria-hidden="true">
  <svg viewBox="0 -960 960 960" fill="currentColor" focusable="false"><path d="…" /></svg>
</span>

<a class="icon icon-has-background" href="mailto:hello@example.com" aria-label="Email us">
  <svg viewBox="0 -960 960 960" fill="currentColor" aria-hidden="true" focusable="false">
    <path d="…" />
  </svg>
</a>
```

The hover rules match `.icon:is(a):hover`, so only a link icon changes color on hover.

<!-- generated:utilities icon -->

| Class                 | Styles                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `icon`                | `:where(.icon) { display: inline-block; width: var(--icon-size); height: var(--icon-size); font-size: var(--icon-size); line-height: var(--icon-size); color: var(--color-icon-normal-color); }`<br>`:where(.icon) * { display: inline-block; width: 100%; height: 100%; object-fit: contain; object-position: center; color: currentColor; }`<br>+ 4 more rules                                                                                                                                                     |
| `icon-has-background` | `:where(.icon.icon-has-background) { --icon-shadow-color: var(--color-icon-normal-has-background-shadow); --icon-shadow-x: var(--icon-has-background-shadow-x); --icon-shadow-y: var(--icon-has-background-shadow-y); --icon-shadow-blur: var(--icon-has-background-shadow-blur); --icon-shadow-spread: var(--icon-has-background-shadow-spread); display: inline-grid; place-items: center; border-style: solid; width: var(--icon-has-background-size); height: var(--icon-has-background-size…`<br>+ 2 more rules |

<!-- /generated -->

## Next.js

The `@systhemaui/next` `Icon` keeps the React API (`Icon`, `Icon.a` and `as`) but renders `Icon.a` through the Next-aware [`LinkHelper`](https://docs.systhema.app/hu/components/utilities.md#linkhelper) instead of a plain `<a>`. Internal links prefetch and navigate on the client, and hash links smooth-scroll, as with `Button.a` and `Card.link`. The social icons of the simple footer use `Icon.a`, so they get the same behavior.

```tsx
import { Icon } from '@systhemaui/next'

export function SettingsShortcut() {
  return (
    <Icon.a href="#cookie-settings" hasBackground aria-label="Cookie settings">
      <svg viewBox="0 -960 960 960" fill="currentColor" aria-hidden="true" focusable="false">
        <path d="M480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Z" />
      </svg>
    </Icon.a>
  )
}
```

## Accessibility

- `Icon` adds no ARIA of its own. Mark a decorative icon `aria-hidden="true"`, and give a real `<svg>` `focusable="false"`.
- A linked `Icon.a` has no visible text, so it needs an `aria-label` that names the destination. The Icon block derives one from the link when the editor leaves it empty.
- Give an icon one name only: an `aria-label` on the link, or `alt` text on an `<img>` inside it, not both.

See [Icons and icon-only controls](https://docs.systhema.app/hu/concepts/accessibility.md#icons-and-icon-only-controls).

## Related

- [Icon block](https://docs.systhema.app/hu/payload/blocks/icon.md)
- [Icon picker](https://docs.systhema.app/hu/payload/editor/icons.md)
- [Button](https://docs.systhema.app/hu/components/button.md)
