pyside-iconify
Give QIcon a data source.
English | 中文 | 日本語 | 한국어 | Español | Français | Deutsch | Русский | Português (BR)
IconWidget("mdi:home", color="red")
One line, one icon. No SVG or PNG files to manage — icons are fetched on demand
from the Iconify ecosystem by name and cached
automatically. Everything still ends up as a standard QIcon, so it works with
any widget that accepts icons.
Status: under active development, not yet published to PyPI. The public API may still change before the first release.
This project is not affiliated with the Iconify project.
Why
| Without | With pyside-iconify |
|---|---|
QIcon("assets/home.svg") |
get_icon("mdi:home") |
| Managing SVG/PNG files and resource paths | Icons by name from the Iconify ecosystem |
| Multiple asset sets for colors and sizes | color, size, rotate as parameters |
| Per-widget icon plumbing | Standard QIcon, works everywhere |
| Manual light/dark theme icon variants | Follows the widget's palette automatically |
Quick start
pip install "pyside-iconify[pyside6]"
from PySide6.QtWidgets import QApplication, QPushButton
from pyside_iconify import IconWidget, get_icon
app = QApplication([])
# A standalone icon widget
icon = IconWidget("mdi:home", size=24, color="red")
# Or hand a standard QIcon to any widget
button = QPushButton("Settings")
button.setIcon(get_icon("mdi:cog", size=20))
app.exec()
That is the whole API for the common case. Icons are downloaded on first use, cached on disk, and rendered locally afterwards.
Highlights
- Theme aware — with no color set, icons follow the widget's text color and switch automatically between light and dark themes; disabled icons fade instead of turning gray (so multi-color icons fade correctly too)
- Full color control — single color,
{original: replacement}mapping for multi-color icons, and per-theme overrides (color_light_theme/color_dark_theme) - Sizes the way you think — numbers,
(w, h),QSize,"24px", or"1.5em"(follows the widget's font) - HiDPI native — sizes are logical pixels; physical pixels are rendered per screen scale factor, no @2x/@3x asset sets
- Loading vs. missing are distinct — loading shows blank, a confirmed miss
shows a built-in placeholder and emits
failed; optionalfallbackicon - QSS friendly —
qss="toolbar primary"tags for grouping, style with nativesetStyleSheet(); priority: parameters → QSS → theme - Animation built in —
spin,pulse,breathe,ping,bounce, plus the self-animating icons ofline-md,meteoconsandsvg-spinnersplay as-is inIconWidget(SMIL only; see below) - Typed and logged — full type hints with
py.typed, standardlogging(silent by default)
Parameters
Shared by IconWidget and get_icon:
get_icon(name, *, size=24, color=None, color_light_theme=None,
color_dark_theme=None, selected_color=None, opacity=1.0,
width=None, height=None, rotate=0, rotate_overflow=False,
spin=False, h_flip=False, v_flip=False)
IconWidget(name, *, ..., hover_color=None, animation=None,
animation_period=None, animation_depth=None, autoplay=True,
speed=1.0, qss=None, parent=None)
| Parameter | Meaning |
|---|---|
name |
Icon name like "mdi:home", or inline icon data |
size |
Number, (w, h), QSize, "24px", or "1.5em" |
color |
A color, or a {original: replacement} mapping |
color_light_theme / color_dark_theme |
Per-theme overrides, win over color |
selected_color |
Color when the item is selected (item views) |
hover_color |
IconWidget / set_icon hover color — explicit opt-in |
opacity |
Overall opacity 0–1; multiplied with color alpha |
width / height |
Non-square icons; win over size |
rotate |
Any angle in degrees, auto-shrunk to avoid clipping |
rotate_overflow |
Keep the original size while rotating; corners may clip |
spin |
Continuous rotation for loading indicators |
animation / animation_period |
IconWidget only: "spin", "pulse", "breathe", "ping" or "bounce"; seconds per cycle |
autoplay / speed |
IconWidget only: play the icon's own SMIL animation automatically; playback speed multiplier |
animation_depth |
How strong the animation is, 0–1 (defaults: pulse 0.25, breathe 0.7, ping 1, bounce 0.25). ping and bounce draw the icon at 1/(1+depth) of the widget to leave room for the ripple and the jump |
h_flip / v_flip |
Horizontal / vertical flip |
qss |
QSS grouping tags, IconWidget[qss~="tag"] selector (IconWidget only) |
Colors accept CSS/SVG names, HEX 3/4/6/8 digit (#RRGGBBAA order),
rgb()/rgba()/hsl()/hsla(), tuples, QColor, and Qt.GlobalColor.
Unparseable colors raise instead of silently turning black.
Animated icons (SMIL)
Some Iconify sets (line-md, meteocons, svg-spinners, eos-icons, ...)
ship icons that animate themselves. IconWidget plays them with no extra code:
IconWidget("line-md:loading-loop", size=48) # loops
IconWidget("line-md:account") # draws itself once, then rests
IconWidget("meteocons:partly-cloudy-day-rain", size=96)
w = IconWidget("line-md:account", autoplay=False, speed=0.5)
w.play(); w.pause(); w.replay(); w.setSpeed(2)
w.isAnimated(), w.isPlaying()
get_icon() and set_icon() return a standard QIcon, which cannot move on
its own, so they show the finished state of the animation. Use IconWidget
for the animated version. is_animated("line-md:account") tells whether an icon
carries an animation (it works without Qt).
Scope: only SMIL is supported (<animate>, <set>, <animateTransform>,
<animateMotion> inside the SVG). Other kinds of animation, such as CSS
animation, scripts, Lottie or GIF, are not played. An icon that uses a SMIL
feature the library does not implement is drawn as a static image of its
finished state and a warning is logged once.
Animated frames are cached as bitmaps (trading memory for speed). A long
looping icon at a large size can take several MiB of the default 32 MiB cache;
raise it with set_cache_limits() if you show many of them at once.
Offline packaging
For air-gapped machines or zero-external-dependency builds, pack icons at release time:
python -m pyside_iconify.pack -o icons.json
from pyside_iconify import load_bundle
load_bundle("icons.json") # at app startup; works inside PyInstaller too
See src/pyside_iconify/pack.py and tests/test_pack_integration.py for the
full CLI and API. Local data always takes priority over the network.
Performance
Three-layer cache (icon data → SVG text → rendered bitmaps) with a memory
budget, per-frame work kept to a cache lookup and one drawPixmap. A 1000-row
QListWidget builds in ~270 ms and scrolls at native speed. For large grids
use item views with get_icon; IconWidget is meant for standalone icon
slots.
Support scope
| Item | Scope |
|---|---|
| Python | 3.10 – 3.14 |
| Qt binding | PySide6 |
| OS | Windows, macOS, Linux (CI on macOS) |
| PySide2/PyQt | Not supported (PyQt6 maybe later) |
Development
uv sync --extra pyside6 --group test
$env:QT_QPA_PLATFORM = "offscreen"
pytest -v
- Contributing guide and release checklist: CONTRIBUTING.md
- Architecture and design decisions: docs/architecture.md
- Roadmap: docs/roadmap.md
- Benchmark:
uv run benchmarks/list_scroll.py
License
MIT. Icon collections are subject to their own licenses; Qt is licensed separately by its copyright holders.
Metadata
Release files for pyside-iconify 1.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| pyside_iconify-1.1.0.tar.gz | 155.7 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pyside_iconify-1.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 266.4 kB
Release files / pyside_iconify-1.1.0.tar.gz
| Download URL | pyside_iconify-1.1.0.tar.gz |
|---|---|
| Size | 155.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e731dd30e2ca31ae0eeb82af4f94b4437d3d01e4ce35fa176cfe63f7208a4a21
|
|
BLAKE2b-256 checksum How to use checksums |
a33c4659089d67ceb11869ce7d87866529e162b54ed5a31121cb8ba066e8fa72
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 26, 2026.
Transparency logRelease files / pyside_iconify-1.1.0-py3-none-any.whl
| Download URL | pyside_iconify-1.1.0-py3-none-any.whl |
|---|---|
| Size | 110.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
723bcb759faf4371682fd7ed9e2b242044399f08ed20c1df910057bfd0611848
|
|
BLAKE2b-256 checksum How to use checksums |
2c2a8c7258d4a50cd0410f0b9783992070e655793810641a06fa6d9bb76de50f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 26, 2026.
Transparency logSecurity for pyside-iconify 1.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for pyside_iconify-1.1.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 26, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.