slint-ui/slint · error

Popup component is a Window item

Error message

Popup component is a Window item

What it means

When computing a popup's placement, Slint assumes the popup component's root item is a `WindowItem` and downcasts the root ItemRef with `.expect("Popup component is a Window item")`. The panic means a component used as a popup has a root element that is not a Window — violating the popup contract that popups are declared with `Window { }` as their root.

Solutions

  1. Ensure the popup component's root element is `Window { ... }` (for PopupWindow, keep the generated root intact)
  2. When instantiating popups via the interpreter/FFI, instantiate the same component that declares the popup and don't re-parent its root
  3. Inspect `component.as_ref().get_item_ref(0)` and verify the item type before calling show_popup

Example fix

// before
let popup = component_definition.create(...); // component rooted in some non-Window element
window.show_popup(&popup, ...);
// after
// in .slint, declare the popup with a Window root and instantiate that component
// component Win := Window { PopupWindow { ... } }
Defensive patterns

Strategy: validation

Validate before calling

// verify the popup component's root is a WindowItem before showing
let root = component.as_ref().get_item_ref(0);
assert!(ItemRef::downcast_pin::<slint::items::WindowItem>(root).is_ok(), "popup root must be a Window");

Type guard

fn is_window_root(comp: &ItemTreeRef) -> bool {
    ItemRef::downcast_pin::<crate::items::WindowItem>(comp.get_item_ref(0)).is_ok()
}

Try / catch

std::panic::catch_unwind(AssertUnwindSafe(|| window.show_popup(&popup, pos, close_on_click))).is_err().then(|| eprintln!("popup root is not a Window"));

Prevention

When it happens

Trigger: Calling `show_popup` (directly or via a PopupWindow in .slint) with a component instance whose root item is not a `WindowItem` — e.g. programmatically instantiated popup trees via the interpreter whose root was changed, or backend/window-adapter code passing the wrong component.

Common situations: Interpreter/FFI users constructing popup components manually and forgetting the `Window` root; custom code re-rooting popup item trees.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of slint-ui/slint@3a7e700487 (2026-09-16). Data as JSON: /api/errors/af9d6653001b50b8. Report an issue: GitHub.

Appendix: source

Thrown at internal/core/window.rs:1752

            if let Some(parent) = popup.parent_item.clone().upgrade() {
                parent.map_to_native_window(
                    parent.geometry().origin + (popup.position_access)().to_euclid().to_vector(),
                )
            } else {
                LogicalPoint::zero()
            }
        };
        let mut active_popups = self.active_popups.borrow_mut();
        let Some(popup) = active_popups.iter_mut().find(|p| p.popup_id == popup_id) else { return };
        match &mut popup.location {
            PopupWindowLocation::ChildWindow(old_location) => {
                let (old_popup_region, new_popup_region) =
                    popup.properties_tracker.as_ref().evaluate_as_dependency_root(|| {
                        let component = ItemTreeRc::borrow_pin(&popup.component);
                        let root_item = component.as_ref().get_item_ref(0);
                        let window_item =
                            ItemRef::downcast_pin::<crate::items::WindowItem>(root_item)
                                .expect("Popup component is a Window item");
                        // Access the properties to set them as dependencies
                        let old_popup_region = LogicalRect::new(
                            *old_location,
                            crate::lengths::LogicalSize::new(
                                window_item.width().0,
                                window_item.height().0,
                            ),
                        );

                        let width = {
                            let layout_info_h = component
                                .as_ref()
                                .layout_info(crate::layout::Orientation::Horizontal);
                            let w = layout_info_h
                                .preferred
                                .max(layout_info_h.min)
                                .min(layout_info_h.max);
                            window_item.width.set(LogicalLength::new(w));

View on GitHub (pinned to 3a7e700487)