forty-cdk
llms.txt

Primitives

Progress

A bar that reflects the completion progress of a task.

forty-cdk/progress WAI-ARIA APG

The bar reflects data-value against data-min / data-max and moves data-state between loading, complete and indeterminate.

60%

Pass a numeric value for a determinate bar, or null for indeterminate ("loading…"). The directive owns ARIA + state; the visual fill is yours via [forProgressIndicator].

When to choose

  • Progress: role="progressbar", for a task advancing toward completion. value accepts null for the indeterminate "working…" state, and announceCompletion announces the end of the task.
  • Meter: role="meter", for a measurement inside a known range (disk used, battery, score), always determinate and bucketed into quality bands. Screen readers announce the two roles differently, so the choice is meaning rather than appearance: if the number is not going anywhere, it is a meter.

Anatomy

<div forProgress [value]="uploaded()" [max]="100" announceCompletion>
  <div forProgressIndicator></div>
</div>

Examples

Indeterminate

A null value puts the bar in indeterminate mode, for loading states whose duration cannot be predicted. In that mode aria-valuenow is omitted and data-state reflects indeterminate.

…

Custom value label

getValueLabel maps value and max to a human string used for aria-valuetext, so screen readers announce '84 MB of 200 MB' instead of a bare number. The same function feeds the visible caption.

project-assets.zip84 MB of 200 MB

API

ForProgress

PropertyTypeDescription
value
input
Current progress in [0, max] (one-way; display-only). null = indeterminate.
Default: null
max
input
Upper bound. A non-positive max is clamped to 1 for ARIA so aria-valuemax always exceeds aria-valuemin (0).
Default: 100
getValueLabel
input
Override for aria-valuetext (e.g. "Step 3 of 5").
Default: —
announceCompletion
input
Announce Complete (or the label) once via aria-live on the loading→complete transition.
Default: —
ariaLabel
input
Accessible name for the progressbar. Prefer a visible label referenced via aria-labelledby when one exists.
Default: null
Data attributeValues
data-stateindeterminate | loading | complete
data-valueclamped value (absent while indeterminate)
data-min0
data-maxthe max value
data-percentage0–100 (absent while indeterminate)

ForProgressIndicator

Visual fill paired with [forProgress]. Reflects the same state so width / transform can be driven from CSS, plus the --for-progress-percentage custom property (e.g. 25%) for use directly in transform / width.

Data attributeValues
data-stateindeterminate | loading | complete
data-valueclamped value (absent while indeterminate)
data-min0
data-maxthe max value
data-percentage0–100 (absent while indeterminate)

Accessibility

Implements the WAI-ARIA Meter pattern, using the progressbar role.

  • role="progressbar" is announced as "progressbar" with the current value as a percentage (or your aria-valuetext if getValueLabel is set).
  • Indeterminate omits aria-valuenow. Per spec, the absence of aria-valuenow is what tells AT the bar is indeterminate. The directive enforces this; data-state="indeterminate" is the CSS hook.
  • Announce sparingly. announceCompletion is opt-in; only enable it on flows where the user explicitly waits for completion (uploads, submissions). For background activity, the silent state change is enough.
  • Keep the bar focusable only if it has actions. A vanilla [forProgress] is non-interactive and should not be in the tab order.

Styling

forty-cdk ships no styles: put your own class on each piece and key your CSS off the data-* attributes listed under API, not off the for* selectors (Styling forty-cdk explains why).

CSS custom properties

PropertyMeaning
--for-progress-percentageCompletion as a CSS percentage (e.g. 25%), set on [forProgressIndicator]. Absent while indeterminate (value === null).
.indicator[data-state='loading'] {
  width: var(--for-progress-percentage, 0%);
}

Wrapping in a design system

Subclass the root and re-provide FOR_PROGRESS_CONTEXT with useExisting pointing at the subclass, since Angular does not inherit a directive's providers; Wrapping non-form roots walks the pattern.