Progress

Show progress through a numeric range.

Try it

Advance or reset the linear and circular indicators. The loading examples animate indeterminately, as in Luma Studio. This preview runs the exact code sample shown on this page.

Open example separately ↗

Basic use

Radix · integration snippet
use gpui::{Context, Entity, Render, Window, div, prelude::*, px};
use xgpui_luma::controls::{button::Button, progress::{Progress, ProgressBuilder, CircularProgressTemplate, ProgressTheme, ProgressLook}};
use xgpui_luma::infra::presenter::HasPresenter;
use xgpui_luma_look_radix as radix;

// Retain Radix colors while giving rings their own size and stroke.
struct CircularTheme(std::sync::Arc<dyn ProgressTheme>);
impl ProgressTheme for CircularTheme {
    fn resolve(&self, enabled: bool, size: xgpui_luma::theme::ControlSize) -> ProgressLook {
        let mut look = self.0.resolve(enabled, size);
        look.size = 48.0;
        look.stroke_width = 4.0;
        look
    }
}

struct Example {
    progress: Progress,
    circular: Progress,
    loading_bar: Progress,
    loading_ring: Progress,
    advance: Entity<Button>,
    reset: Entity<Button>,
    completed: f32,
}

impl Example {
    fn new(cx: &mut Context<Self>) -> Self {
        let look = cx.try_global::<radix::Look>().cloned().unwrap_or_else(radix::Look::built_in);
        let circular_template = std::sync::Arc::new(CircularProgressTemplate::new(
            std::sync::Arc::new(CircularTheme(radix::progress_theme(&look))),
        ));
        let progress = radix::Progress::new("progress")
            .range(0..100).value(0.0).motion_enabled(true).spawn(cx);
        let circular = ProgressBuilder::new("circular").circular()
            .template(circular_template.clone()).range(0..100).value(0).motion_enabled(true).spawn(cx);
        let loading_bar = radix::Progress::new("loading-bar")
            .indeterminate(true).spawn(cx);
        let loading_ring = ProgressBuilder::new("loading-ring").circular().template(circular_template)
            .indeterminate(true).spawn(cx);
        let advance = radix::Button::new("advance")
            .label("Advance +10%")
            .on_click(cx, |owner: &mut Self, cx| {
                owner.set_progress((owner.completed + 10.0).min(100.0), cx);
            })
            .spawn(cx);
        let reset = radix::Button::new("reset")
            .label("Reset")
            .on_click(cx, |owner: &mut Self, cx| owner.set_progress(0.0, cx))
            .spawn(cx);
        Self { progress, circular, loading_bar, loading_ring, advance, reset, completed: 0.0 }
    }

    fn set_progress(&mut self, value: f32, cx: &mut Context<Self>) {
        self.completed = value;
        self.progress.update(cx, |progress, cx| progress.set_value(value, cx));
        self.circular.update(cx, |progress, cx| progress.set_value(value, cx));
        self.advance.update(cx, |button, cx| button.set_enabled(value < 100.0, cx));
        cx.notify();
    }
}

impl Render for Example {
    fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
        div().flex().flex_col().gap_3().w(px(320.0))
            .child("Linear progress")
            .child(self.progress.clone())
            .child(div().flex().items_center().gap_3()
                .child(self.circular.clone()).child("Circular progress"))
            .child(format!("{:.0}% complete", self.completed))
            .child(div().flex().gap_2()
                .child(self.advance.clone()).child(self.reset.clone()))
            .child("Indeterminate loading")
            .child(self.loading_bar.clone())
            .child(self.loading_ring.clone())
    }
}

Click Advance +10% to animate the progress and update the percentage. At 100%, Advance is disabled; Reset returns to zero and enables it again. Render this view inside an initialized Luma application.

SDK behavior & customization

A read-only indicator. Update its value from application state; it is not a value picker.

Relevant contracts: ProgressRenderModel.

Use the module’s template contract for structural changes. Builder modifiers and item templates vary by control.

Application interaction

Progress is read-only and exposes no ProgressEvent. In this example, Button’s named on_click callbacks update application state and call set_value. For real work, call the same update method as tasks complete. motion_enabled(true) animates transitions between values; it does not advance progress automatically.

Source

SDK module · Radix adapter