Progress Ring
Progress rings provide users with visual feedback about the status of ongoing processes through a circular progress indicator. This component displays both determinate progress with specific percentages and indeterminate loading states.
import {ProgressRingModule} from "@qualcomm-ui/angular/progress-ring"Overview
The progress ring can be in one of two states:
- indeterminate: the default state.
- determinate: assumed when the value prop is passed.
Indeterminate progress rings keep users informed that work is happening when timeframes are unknown.
Examples
Simple
The simple API bundles all subcomponents together into a single directive.
<div label="Label" q-progress-ring></div>
Child Directives
Provide child directives to customize specific elements while keeping the simple API's default structure.
<div q-progress-ring>
<div q-progress-ring-label>Label</div>
</div>
Composite
Build with the composite API for granular control. This API requires you to provide each subcomponent, but gives you full control over the structure.
<div q-progress-ring-root>
<div q-progress-ring-circle-container>
<svg q-progress-ring-circle></svg>
</div>
<div q-progress-ring-label>Loading...</div>
</div>
Controlled Value
When the value prop is set, the filled portion of the circle will represent the total percent relative to max and min. This is referred to as the "determinate" state.
<div q-progress-ring size="lg" [value]="value()">
<svg aria-label="Loading" q-progress-ring-circle></svg>
<div *progressRingContext="let context" q-progress-ring-value-text>
{{ context.valuePercent }}%
</div>
</div>
Value Text
Display the value text using the q-progress-ring-value-text directive. The value text only shows when the size is lg or xl.
import {Component, type OnInit, signal} from "@angular/core"
import {useOnDestroy} from "@qualcomm-ui/angular-core/common"
import {ProgressRingModule} from "@qualcomm-ui/angular/progress-ring"
@Component({
imports: [ProgressRingModule],
selector: "progress-ring-value-text-demo",
template: `
<div label="Loading..." q-progress-ring size="lg" [value]="value()">
<div *progressRingContext="let context" q-progress-ring-value-text>
{{ context.valuePercent }}%
</div>
</div>
`,
})
export class ProgressRingValueTextDemo implements OnInit {
protected readonly onDestroy = useOnDestroy()
protected readonly value = signal(0)
ngOnInit() {
const timer = setInterval(() => {
this.value.update((prevValue) => {
if (prevValue === 100) {
return 0
}
return prevValue + 10
})
}, 1000)
this.onDestroy(() => {
clearInterval(timer)
})
}
}Sizes
Use the size prop to change the size of the circle.
import {Component, type OnInit, signal} from "@angular/core"
import {useOnDestroy} from "@qualcomm-ui/angular-core/common"
import {ProgressRingModule} from "@qualcomm-ui/angular/progress-ring"
@Component({
imports: [ProgressRingModule],
selector: "progress-ring-sizes-demo",
template: `
<div class="flex items-center gap-4">
<div
class="grid grid-cols-3 items-center justify-items-center gap-x-8 gap-y-4"
>
<div class="font-heading-xs text-neutral-primary">xxs</div>
<div q-progress-ring size="xxs" [value]="value()"></div>
<div q-progress-ring size="xxs"></div>
<div class="font-heading-xs text-neutral-primary">xs</div>
<div q-progress-ring size="xs" [value]="value()"></div>
<div q-progress-ring size="xs"></div>
<div class="font-heading-xs text-neutral-primary">sm</div>
<div q-progress-ring size="sm" [value]="value()"></div>
<div q-progress-ring size="sm"></div>
<div class="font-heading-xs text-neutral-primary">md</div>
<div q-progress-ring size="md" [value]="value()"></div>
<div q-progress-ring size="md"></div>
<div class="font-heading-xs text-neutral-primary">lg</div>
<div q-progress-ring size="lg" [value]="value()"></div>
<div q-progress-ring size="lg"></div>
<div class="font-heading-xs text-neutral-primary">xl</div>
<div q-progress-ring size="xl" [value]="value()"></div>
<div q-progress-ring size="xl"></div>
</div>
</div>
`,
})
export class ProgressRingSizesDemo implements OnInit {
protected readonly onDestroy = useOnDestroy()
protected readonly value = signal(0)
ngOnInit() {
const timer = setInterval(() => {
this.value.update((prevValue) => {
if (prevValue === 100) {
return 0
}
return prevValue + 10
})
}, 1000)
this.onDestroy(() => {
clearInterval(timer)
})
}
}Thickness
Use the thickness prop to change the pixel width of the track and bar.
<div class="py-2" q-progress-ring size="lg" [thickness]="8"></div>
Disabled
Use the disabled prop to indicate that the progress indicator is inactive.
<div disabled label="Indeterminate" q-progress-ring size="lg"></div>
<div
disabled
label="Determinate"
q-progress-ring
size="lg"
value="64"
valueText="64%"
></div>
Accessibility
- When the value is supplied, the component automatically provides the corresponding
aria-value*attributes to the element. - The progress element is automatically marked with
role="progressbar". - The label is automatically associated with the progress ring. If you omit the label property, the
aria-labelof the progress element defaults to the value when determinate, and "Loading" when indeterminate.
Explorer
Component Anatomy
Hover to highlight, click to view API
API
q-progress-ring
The q-progress-ring extends the q-progress-ring-root with the following props:
string<div q-progress-ring-error-text>...</div>
string<div q-progress-ring-label>...</div>
string<div q-progress-ring-value-text>...</div>
ProgressApi
The ProgressApi is accessible from the template via the progressRingContext structural directive:
<ng-container *progressRingContext="let context">
{{ context.valuePercent }}%
</ng-container>booleannumbernumber(
value: number,
) => void
| 'indeterminate'
| 'complete'
| 'loading'
value.numbernumbermin
and max values.Composite API
q-progress-ring-root
number'ltr' | 'rtl'
booleantrue, the progress is disabled.| 'primary'
| 'neutral'
booleantrue, the progress is marked as invalid.numbernumber| 'xxs'
| 'xs'
| 'sm'
| 'md'
| 'lg'
| 'xl'
| number
| string
| number
The default value varies based on the size of the progress circle.
numbernumberclass'qui-progress-ring__root'data-disableddata-invaliddata-maxnumberdata-progress-part'root'data-size| 'xxs'
| 'xs'
| 'sm'
| 'md'
| 'lg'
| 'xl'
| number
data-state| 'indeterminate'
| 'complete'
| 'loading'
data-valuenumberstyleq-progress-ring-label
stringclass'qui-progress-ring__label'data-progress-part'label'q-progress-ring-value-text
class'qui-progress-ring__value-text'data-invaliddata-progress-part'value-text'hiddenbooleanq-progress-ring-error-text
stringclass'qui-progress-ring__error-text'data-progress-part'error-text'hiddenbooleanq-progress-ring-circle-container
class'qui-progress-ring__circle-container'data-progress-part'circle-container'q-progress-ring-circle
stringclass'qui-progress-ring__circle'data-disableddata-emphasis| 'primary'
| 'neutral'
data-progress-part'circle'data-size| 'xxs'
| 'xs'
| 'sm'
| 'md'
| 'lg'
| 'xl'
| number
data-state| 'indeterminate'
| 'complete'
| 'loading'
styleq-progress-ring-track
class'qui-progress-ring__track'data-disableddata-progress-part'circle-track'data-size| 'xxs'
| 'xs'
| 'sm'
| 'md'
| 'lg'
| 'xl'
| number
data-state| 'indeterminate'
| 'complete'
| 'loading'
q-progress-ring-bar
class'qui-progress-ring__bar'data-disableddata-emphasis| 'primary'
| 'neutral'
data-invaliddata-maxnumberdata-progress-part'circle-bar'data-size| 'xxs'
| 'xs'
| 'sm'
| 'md'
| 'lg'
| 'xl'
| number
data-state| 'indeterminate'
| 'complete'
| 'loading'
style