RepoPilotOpen in app →

iced-rs/iced

A cross-platform GUI library for Rust, inspired by Elm

Healthy

Healthy across all four use cases

weakest axis
Use as dependencyHealthy

Permissive license, no critical CVEs, actively maintained — safe to depend on.

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • Last commit 1d ago
  • 7 active contributors
  • MIT licensed
Show all 6 evidence items →
  • CI configured
  • Tests present
  • Single-maintainer risk — top contributor 87% of recent commits

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Healthy" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Healthy
[![RepoPilot: Healthy](https://repopilot.app/api/badge/iced-rs/iced)](https://repopilot.app/r/iced-rs/iced)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/iced-rs/iced on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: iced-rs/iced

Generated by RepoPilot · 2026-05-09 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/iced-rs/iced shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

GO — Healthy across all four use cases

  • Last commit 1d ago
  • 7 active contributors
  • MIT licensed
  • CI configured
  • Tests present
  • ⚠ Single-maintainer risk — top contributor 87% of recent commits

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live iced-rs/iced repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/iced-rs/iced.

What it runs against: a local clone of iced-rs/iced — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in iced-rs/iced | Confirms the artifact applies here, not a fork | | 2 | License is still MIT | Catches relicense before you depend on it | | 3 | Default branch master exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 31 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>iced-rs/iced</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of iced-rs/iced. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/iced-rs/iced.git
#   cd iced
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of iced-rs/iced and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "iced-rs/iced(\\.git)?\\b" \\
  && ok "origin remote is iced-rs/iced" \\
  || miss "origin remote is not iced-rs/iced (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
  && ok "license is MIT" \\
  || miss "license drift — was MIT at generation time"

# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
  && ok "default branch master exists" \\
  || miss "default branch master no longer exists"

# 4. Critical files exist
test -f "core/src/lib.rs" \\
  && ok "core/src/lib.rs" \\
  || miss "missing critical file: core/src/lib.rs"
test -f "core/src/element.rs" \\
  && ok "core/src/element.rs" \\
  || miss "missing critical file: core/src/element.rs"
test -f "core/src/widget.rs" \\
  && ok "core/src/widget.rs" \\
  || miss "missing critical file: core/src/widget.rs"
test -f "core/src/renderer.rs" \\
  && ok "core/src/renderer.rs" \\
  || miss "missing critical file: core/src/renderer.rs"
test -f "Cargo.toml" \\
  && ok "Cargo.toml" \\
  || miss "missing critical file: Cargo.toml"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 31 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~1d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/iced-rs/iced"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

Iced is a cross-platform GUI library for Rust inspired by Elm's architecture, providing a type-safe, reactive programming model with built-in widgets and two renderers (wgpu GPU-accelerated and tiny-skia software fallback). It enables developers to build responsive desktop applications for Windows, macOS, Linux, and WebAssembly using Rust with a simple, batteries-included API. Monorepo structured as: core/ (fundamental types like Element, Event, Font, Color, Alignment); multiple renderer crates (iced_renderer, wgpu/, tiny_skia/); iced_widget/ (built-in widgets); iced_winit/ (windowing shell); runtime/ (renderer-agnostic runtime); beacon/ (telemetry client); benches/ (CPU and wgpu performance tests). Top-level src/ packages it all; examples/ demonstrates the API.

👥Who it's for

Rust developers building desktop applications who want type safety and functional reactive programming patterns; systems programmers integrating GUI rendering into existing Rust projects via the renderer-agnostic native runtime; Elm developers porting to Rust who appreciate the Elm Architecture pattern.

🌱Maturity & risk

Actively developed with comprehensive CI/CD (audit, build, check, lint, test, format, document workflows in .github/workflows/), extensive test coverage, and explicit experimental status in README. The project has two production-ready renderers (wgpu and tiny-skia) and modular architecture, but README states 'Iced is currently experimental software'—suitable for serious projects but expect breaking API changes.

Moderate risk: monorepo with 2.4M lines of Rust code across multiple tightly-coupled crates (core, widget, renderer, winit, runtime) means changes cascade widely. Large dependency tree through wgpu (Vulkan/Metal/DX12 support) and windowing layer. Single active maintainer community (hecrj) with occasional drive-by contributors. ROADMAP.md and issue backlog suggest ongoing prioritization, but experimental status means no stability guarantees.

Active areas of work

Active development on multi-renderer support and performance optimization (benches/wgpu.rs and benches/cpu.rs visible); experimental features in progress (debug tooling visible in features: 'debug', 'time-travel', 'hot reloading', 'tester'); CI focused on audit, format, lint compliance. ROADMAP.md and CHANGELOG.md document planned and completed work.

🚀Get running

Clone, setup Rust, build and run examples:

git clone https://github.com/iced-rs/iced.git
cd iced
cargo build --release
cargo run --example counter

For web targets, enable wasm feature. Development requires Rust 1.70+ (check rust-version in Cargo.toml).

Daily commands: Development: cargo run --example <name> (see examples/ for available demos). With all features: cargo run --all-features --example <name>. Debug build: cargo run --example counter (debug metrics on F12). Test: cargo test. Lint: cargo clippy, cargo fmt --check.

🗺️Map of the codebase

  • core/src/lib.rs — Main entry point for the core library; defines public API surface and re-exports fundamental types like Element, Widget, and Theme that all applications depend on
  • core/src/element.rs — Core abstraction for composable UI elements; every widget must implement this trait, making it the load-bearing abstraction for the entire framework
  • core/src/widget.rs — Widget trait definition and base widget operations; foundational for all UI component implementations and state management
  • core/src/renderer.rs — Renderer trait that abstracts over wgpu and other backends; critical for understanding how Iced decouples rendering from widget logic
  • Cargo.toml — Workspace root configuration defining all feature flags (wgpu, tiny-skia, web-colors, platform backends) and dependency versions that drive the entire project
  • core/src/widget/tree.rs — Widget tree and state management system; essential for understanding how Iced maintains component hierarchies and mutable state across renders
  • core/src/theme.rs — Theme system and styling abstractions; defines how applications customize appearance globally

🛠️How to make changes

Add a new custom Widget

  1. Create a new file in your crate or in iced, e.g., my_widget.rs (core/src/widget.rs)
  2. Implement the Widget trait with methods: new(), width(), height(), layout(), draw(), on_event(), operate(), and overlay() (core/src/widget.rs)
  3. Define your widget's state (if needed) and message type; store state in tree.state during layout/event phases (core/src/widget/tree.rs)
  4. Return a styled Element from your update or view function wrapping your widget (core/src/element.rs)

Add a new Theme variant or styling preset

  1. Define your theme colors and styling in a new enum variant or struct (core/src/theme.rs)
  2. Implement color palette methods (e.g., primary(), secondary()) matching the Palette interface (core/src/theme/palette.rs)
  3. Add theme application logic in renderer-specific code (e.g., in iced_renderer) to map theme colors to widget styles (core/src/theme.rs)
  4. Export the new theme from core/src/lib.rs and document in README or CHANGELOG (core/src/lib.rs)

Add a new platform/backend renderer

  1. Create a new backend crate (e.g., iced_renderer_custom) with Cargo.toml mirroring dependencies (Cargo.toml)
  2. Implement the Renderer trait from core/src/renderer.rs with methods like with_layer(), with_transformation(), fill(), text() (core/src/renderer.rs)
  3. Add a feature flag in the root Cargo.toml to conditionally include your backend (Cargo.toml)
  4. Update the main iced crate to optionally depend on your new backend behind the feature flag (Cargo.toml)

Add a new input event type or keyboard key

  1. Add a new variant to the appropriate enum in core/src/keyboard/key.rs or define a new struct for custom input (core/src/keyboard/key.rs)
  2. Update the Event enum in core/src/event.rs if introducing a new top-level event category (core/src/event.rs)
  3. Implement event propagation logic in core/src/shell.rs to route the new event to widgets (core/src/shell.rs)
  4. Handle the new event in widgets via the Widget::on_event() method (core/src/widget.rs)

🔧Why these technologies

  • Elm-inspired architecture (Model-View-Update) — Provides predictable, functional state management; eliminates entire classes of bugs from mutable shared state; simplifies reasoning about UI behavior
  • Trait-based renderer abstraction (Renderer trait) — Decouples widgets from rendering implementation; enables swapping backends (wgpu, tiny-skia, custom) without changing widget code; supports both 2D and 3D rendering
  • Flexbox layout engine (derived from Druid) — Provides predictable, constraint-based layout matching web standards; handles responsive design without manual position calculation
  • Widget tree with operation traversal — Enables generic widget operations (focus, scroll, text selection) without coupling specific widgets; allows

🪤Traps & gotchas

No required env vars for basic builds. Subfeature interdependencies: enabling 'debug' without 'iced_devtools' dep fails; 'time-travel' requires 'debug'; 'hot' needs 'iced_debug/hot' and will not work in release builds. wgpu renderer requires native GPU drivers (Vulkan/Metal/DX12)—falls back to tiny-skia if unavailable, but tiny-skia incurs a soft licensing constraint (Zlib). Cross-platform build: Cross.toml required for ARM targets; winit/wgpu on Linux needs X11 or Wayland at runtime. Clipboard operations (core/src/clipboard.rs) are OS-specific and may silently fail without sandboxing overrides.

🏗️Architecture

💡Concepts to learn

  • The Elm Architecture — Iced's entire program model (State, Messages, View, Update) is built on Elm's functional reactive pattern—understanding this is prerequisite to writing any Iced app
  • Renderer abstraction / trait-based polymorphism — Iced achieves swappable renderers (wgpu, tiny-skia, future renderers) via trait objects in iced_renderer/; critical to grasping how new rendering backends integrate
  • Layout engine (flexbox-inspired) — Widget positioning is computed via a layout pass independent of rendering; Iced uses Taffy-like constraints to recursively measure and place elements—essential to debugging UI spacing issues
  • Widget trait and element composition — Custom widgets implement Widget trait (update, view, etc.); Element wraps any widget and enables type erasure—foundational to Iced's composable UI abstraction
  • Message routing and event handling — User interactions flow through Event → widget-specific Message types → Application::update; understanding this path is crucial for interactive features (buttons, text inputs, etc.)
  • Future-based async/await in GUI — Iced's Command type wraps futures for non-blocking operations (network, file I/O); integrating async Rust into the elm-inspired synchronous update loop requires careful handling
  • WGSL shading (GPU renderer only) — The wgpu renderer uses WGSL (WebGPU Shading Language) for custom render passes; 20K lines in repo indicate substantial shader code for advanced rendering features
  • xi-editor/druid — Alternative Rust GUI library with data-first architecture; direct competitor solving same problem with different patterns
  • DioxusLabs/dioxus — React-like Rust UI framework supporting desktop via native renderers; appeals to web developers seeking Rust parity
  • tauri-apps/tauri — Cross-platform desktop framework using Rust + WebView; complements Iced for teams preferring web stack but needing native performance
  • gfx-rs/wgpu — Core graphics abstraction Iced depends on; Iced's GPU renderer is built atop wgpu's Vulkan/Metal/DX12 backends
  • rust-windowing/winit — Window and input handling layer Iced wraps in iced_winit/; fundamental to cross-platform event delivery

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add comprehensive unit tests for core/src/keyboard and core/src/mouse modules

The keyboard and mouse event handling modules (core/src/keyboard/, core/src/mouse/) are foundational to user interaction but appear to lack dedicated unit tests in the visible structure. These modules handle critical input processing including key events, modifiers, button clicks, and cursor interactions. Adding thorough test coverage would improve reliability and serve as regression protection for input handling changes.

  • [ ] Create core/src/keyboard/tests.rs with tests for key parsing, location detection, and modifier combinations
  • [ ] Create core/src/mouse/tests.rs with tests for button detection, click handling, cursor states, and interaction variants
  • [ ] Add property-based tests for keyboard key serialization/deserialization using proptest
  • [ ] Ensure CI runs these tests in the existing test.yml workflow
  • [ ] Document tested edge cases in comments (e.g., modifier key combinations, cursor boundary conditions)

Create integration tests for layout system against core/src/layout/flex.rs flex implementation

The layout system has a DRUID_LICENSE file reference and flex.rs implements critical layout logic. There's no visible dedicated integration test file that validates layout calculation correctness across various constraint scenarios. This would prevent layout regressions when the flex implementation is modified and validate cross-platform consistency.

  • [ ] Create benches/layout_tests.rs or tests/layout_integration.rs with test cases for flex layout scenarios
  • [ ] Add tests for min/max constraints from core/src/layout/limits.rs against actual flex output
  • [ ] Test padding, spacing, and alignment combinations using the layout node structure
  • [ ] Include edge cases: zero-width containers, overflow scenarios, nested flex layouts
  • [ ] Add benchmark comparisons to benches/cpu.rs or benches/wgpu.rs for layout performance regression detection

Add feature-gated documentation examples and tests for image/svg/canvas widgets

The Cargo.toml shows optional features for image, svg, and canvas widgets but these are not well-represented in core/README.md or core/src/lib.rs documentation. New contributors need clear examples of how to use feature-gated widgets. Adding conditional doc tests would validate that examples compile and work correctly for each feature combination.

  • [ ] Update core/README.md with feature-gated examples showing image, svg, canvas, and qr_code widget usage
  • [ ] Add #[cfg_attr(feature = "...", doc = include_str!("examples/widget_name.md"))] to relevant widget modules
  • [ ] Create examples/image_widget.rs, examples/svg_widget.rs, examples/canvas_widget.rs with full runnable code
  • [ ] Add doc tests in iced_widget crate that validate each feature's widget compilation with correct feature flags
  • [ ] Update .github/workflows/document.yml to test doc examples with different feature combinations

🌿Good first issues

  • Add missing documentation examples to core/src/gradient.rs and core/src/content_fit.rs—these public enums lack code snippets in doc comments despite being exposed in the prelude
  • Expand test coverage for keyboard event routing (core/src/keyboard/event.rs and core/src/keyboard.rs)—currently minimal test visibility in the file structure despite complex modifier state handling
  • Write a tutorial example (examples/theming.rs or examples/custom_fonts.rs) demonstrating core/src/font.rs and core/src/color.rs integration—the crate advertises 'batteries-included' but typography docs are sparse

Top contributors

Click to expand

📝Recent commits

Click to expand
  • 51e9c2d — Merge pull request #3326 from edwloef/custom-theme-cow (hecrj)
  • 674bcc9 — modify Custom::new to use impl Into<Cow<'static, str>> (edwloef)
  • cf09909 — Merge pull request #3323 from iced-rs/wgpu-29 (hecrj)
  • f7fe5fb — Enforce Send + Sync for Display trait on Wasm (hecrj)
  • c3a3b54 — Provide display handle to InstanceDescriptor (hecrj)
  • 2a19ff5 — Update dependencies in Cargo.lock (hecrj)
  • 73c224e — Update wgpu to 29 (hecrj)
  • 4e0bdcf — Merge pull request #3322 from iced-rs/cosmic-text-0.19 (hecrj)
  • 12c5c08 — Set default fonts explicitly per OS in FontSystem (hecrj)
  • 7b3ec15 — Update cosmic-text to 0.19 (hecrj)

🔒Security observations

The iced GUI library shows good security practices with automated auditing and a modular feature system. However, there are medium-severity concerns around incomplete documentation of complex features (especially GPU rendering with multiple backends and image codec support), experimental debugging features, and the parsing of potentially untrusted content in SVG/Canvas/Markdown features. The library appears well-maintained with active CI/CD pipelines. Primary recommendations: complete feature documentation with security implications, implement input validation guidance for content rendering features, and establish a formal security disclosure policy.

  • Medium · Incomplete Feature Flag Documentation — Cargo.toml - features section. The features list in Cargo.toml is incomplete - the 'markdown' feature description ends abruptly with '# Enables'. This could indicate missing or incomplete security-related feature documentation that might affect how the library handles untrusted input. Fix: Complete all feature documentation and ensure security implications of each feature are clearly documented, especially for markdown, canvas, and SVG rendering features that may parse untrusted content.
  • Medium · GPU Renderer with Multiple Backends — Cargo.toml - default features and wgpu configuration. The default features enable wgpu with all backends (Vulkan, Metal, DX12, OpenGL, WebGPU). This increases the attack surface, especially with hardware-specific graphics drivers which may have their own vulnerabilities. Fix: Document security implications of each GPU backend. Consider providing secure defaults that minimize the number of enabled backends, or require explicit opt-in for all backends.
  • Low · Image Widget with Multiple Codecs — Cargo.toml - image feature. The image feature includes support for multiple image codecs through the 'image' crate with default features enabled. Image processing libraries historically have had parsing vulnerabilities in various codec implementations. Fix: Document which codecs are enabled by default. Consider providing 'image-without-codecs' as the default option. Ensure the 'image' crate dependency is regularly updated and audited.
  • Low · SVG and Canvas Rendering without Input Validation Documentation — Cargo.toml - svg and canvas features. SVG and canvas widgets are enabled and could potentially render untrusted content. Without clear documentation on input validation, there's risk of SVG-based attacks or canvas exploitation. Fix: Document security considerations for SVG and canvas rendering, including guidance on validating/sanitizing user-provided content. Ensure features include appropriate input validation mechanisms.
  • Low · Experimental Features Enabled by Default — Cargo.toml - time-travel and hot features. Features marked as 'very experimental' in comments (time-travel debugging, hot reloading) have potential security implications if exposed. While not enabled by default, their experimental nature suggests incomplete security review. Fix: Ensure experimental features include clear warnings in documentation. Perform thorough security review before graduation from experimental status. Consider requiring explicit opt-in and warnings in code.
  • Low · Missing Security Policy Documentation — Repository root. No SECURITY.md file visible in the repository structure. While audit.yml exists for dependency checking, there's no documented security reporting policy or vulnerability disclosure process. Fix: Add a SECURITY.md file documenting responsible disclosure process, supported versions for security updates, and how to report vulnerabilities securely.

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Healthy signals · iced-rs/iced — RepoPilot