Skip to content

Progress ring and Spinner Use cases - #1371

Open
jamesnw wants to merge 12 commits into
mainfrom
progress-ring-use-case
Open

Progress ring and Spinner Use cases#1371
jamesnw wants to merge 12 commits into
mainfrom
progress-ring-use-case

Conversation

@jamesnw

@jamesnw jamesnw commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Fixes #1247, #1250

Given that these link to each other and have overlap, I wanted to work on them together.

I think there is a case for adding an indeterminate state to the progress ring, but opted to have them separate, as that pattern seemed to be common in design libraries.

Both have alternate markup possibilities, which I mention but opted not to expand on.

@github-actions
github-actions Bot requested review from LeaVerou and bramus August 24, 2026 17:42
@yesdhaniidan-web

This comment was marked as off-topic.

@bramus bramus left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just some minor nits.

Comment thread guides/ui-components/progress-ring/guide.md Outdated
Comment thread guides/ui-components/spinner/demo.html Outdated
Comment thread guides/ui-components/spinner/guide.md Outdated
Comment thread guides/ui-components/progress-ring/guide.md Outdated
Comment thread guides/ui-components/spinner/guide.md Outdated
- Styling the component with `conic-gradient()` to create a visual "trail" and `mask-image` to hollow out the center into a ring.
- Animating the spinner efficiently using CSS transforms and respecting `prefers-reduced-motion` to ensure a comfortable experience for all users.

See the [Progress Ring guide](../progress-ring/guide.md) for handling determinate tasks with a known duration.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use GUIDE_REF macro

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated.

Comment thread guides/ui-components/progress-ring/guide.md Outdated
Comment thread guides/ui-components/progress-ring/expectations.md
Comment thread guides/ui-components/spinner/guide.md Outdated
Comment thread guides/ui-components/spinner/guide.md Outdated
@bramus
bramus self-requested a review August 25, 2026 14:00

@bramus bramus left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have no further remarks. Thanks for the updates!

@LeaVerou LeaVerou left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implementation

  • Why 2 elements? I might be missing something (e.g. some a11y reason), but why are we hiding the actual semantic element here? This seems to confer no benefit over the div + ARIA approach, it just adds boilerplate.
    The idea of this guide was is to style the <progress> itself.
  • I'd use mask as a fallback and background-clip: border-area as the primary implementation, as it's more flexible and closer to user intent.
  • This could also be a good use case for the new accentcolor system color keyword once it ships. Does it have a web-feature id? If not, we could use a tmp- (see #1256)
  • Even generated content still works in that mode, so progress-ring could be a good use case for expanded attr() too! Make sure to apply a counter rotate. If that's janky, could switch to no rotate and doing it all in the start and end angles.

Visual design

  • I'd avoid a gradient for the spinner. It looks dated, the current trend is flat line with either a rotate (e.g. shadcn) or irregular animation (e.g. WA).
  • Another thing that applies to both the progress-ring and the spinner is that we often want rounded line caps. I'm not convinced they matter tremendously in such a small size, but they can be done with radial-gradient() if need be. Might be worth a note.

I quickly Clauded this codepen to illustrate some of these: https://codepen.io/leaverou/pen/EaWaaGm

@jamesnw

jamesnw commented Aug 27, 2026

Copy link
Copy Markdown
Contributor Author

Implementation

* **Why 2 elements?** I might be missing something (e.g. some a11y reason), but why are we hiding the actual semantic element here? This seems to confer no benefit over the div + ARIA approach, it just adds boilerplate.
  The idea of this guide was is to style the `<progress>` itself.

There isn't an a11y issue. For the progress ring, we need a wrapper for the inner content anyways, and that carried over for the spinner. It was also to avoid the block that hides all the prefixed progress-bar and progress-values. I moved the spinner to style <progress> directly- should I do that for progress-ring as well?

* I'd use mask as a fallback and `background-clip: border-area` as the primary implementation, as it's more flexible and closer to user intent.

Done.

* This could also be a good use case for the new `accentcolor` system color keyword once it ships. Does it have a web-feature id? If not, we could use a `tmp-` (see #1256)

Hmm, the accentcolor system color keyword is currently part of the system-color web feature, and hidden by a compute_from, so it appears to be widely available. It does appear to be newly available - however, testing and MDN seem to point to it only working in installed PWAs? Is that correct?

* Even generated content still works in that mode, so progress-ring could be a good use case for expanded `attr()` too! Make sure to apply a counter rotate. If that's janky, could switch to no rotate and doing it all in the start and end angles.

This was fairly straightforward to do with attr(), but I'm not sure what you mean by a "counter rotate".

Visual design

* I'd avoid a gradient for the spinner. It looks dated, the current trend is flat line with either a rotate (e.g. [shadcn](https://ui.shadcn.com/docs/components/base/spinner)) or irregular animation (e.g. [WA](https://webawesome.com/docs/components/spinner)).

Removed the gradient.

* Another thing that applies to both the progress-ring and the spinner is that we often want rounded line caps. I'm not convinced they matter tremendously in such a small size, but they can be done with `radial-gradient()` if need be. Might be worth a note.

I added this as solely a note in the guide, but didn't provide code for this- is that ok?

@jamesnw
jamesnw requested a review from LeaVerou August 27, 2026 17:38
Comment thread guides/ui-components/spinner/guide.md Outdated
}
```

You can also use a `radial-gradient` to make rounded end caps.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's ok not to include this in the demo for simplicity but we should provide a little more guidance: e.g. use trigonometry to position them at the ends of the radial gradient, how to size them, etc.

Also, I'd add that while this is barely visible in thinner rings, it starts making a significant difference in thicker ones, so it may not be the worst idea to just include it always.

Image

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't get to this in the initial revision pass, but think it makes sense to include.

Comment thread guides/ui-components/spinner/demo.html Outdated
var(--spinner-timing) infinite;
}

@keyframes spinner-rotate {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even if the demo only includes a basic rotate, I think it would be useful to add a little guidance for how to implement the more irregular effect as I see it more frequently in polished UIs these days (I was actually surprised ShadCN only did a basic rotate).

We could even do it by default, it's only marginally more complex and adds a lot of fidelity to the design.
It's basically something like:

animation:
			progress-spin var(--speed) linear infinite,
			progress-dash 1.5s ease-in-out infinite;

with the animations being something like:

@keyframes progress-spin {
	to { rotate: 1turn; }
}

@keyframes progress-dash {
	from { --arc-start: 0deg;   --arc-end: 3deg; }
	50%  { --arc-start: 100deg; --arc-end: 358deg; }
	to   { --arc-start: 355deg; --arc-end: 360deg; }
}

(and suitable registrations for the properties)

What do you think?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added this. I don't love the fallback for registered properties (!('registerProperty' in CSS') in JS setting the animation duration for progress-dash to 0), perhaps there's a better way?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just saw this. Agreed I don't like the JS fallback. Hmmm.

One way to do it purely in CSS is to define a property that contains , progress-dash 1.5s ease-in-out infinite as the initial value, then use it like var(--progress-dash-animation, ). No property registration, the property would be empty and you'd just get blank.
It does add a pointless registered property, but we're already registering properties so…

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like that more, conceptually. VSCode's CSS parser doesn't like the preceeding comma, but that's something to look into another day...

Comment thread guides/ui-components/progress-ring/guide.md Outdated
Comment thread guides/ui-components/spinner/guide.md
Comment thread guides/ui-components/progress-ring/guide.md
@LeaVerou

Copy link
Copy Markdown
Collaborator

There isn't an a11y issue. For the progress ring, we need a wrapper for the inner content anyways, and that carried over for the spinner.
[...]
I moved the spinner to style <progress> directly- should I do that for progress-ring as well?

I was going to say we don't if it's just a matter of showing a simple unformatted percentage, but I had forgotten generated content on <progress> still doesn't work in Gecko. Bummer.

In that case, do we actually need the extra <progress> element? The way I see it, it adds complexity (we now have two elements, and we need to make sure they are aligned etc) for little discernible benefit over the ARIA pattern.

One potential way forwards is: use <progress> if you don't need content, use the ARIA pattern if you do. We can also use a <progress> instead of ::before as a fallback when background-clip: border-area isn't available (masking the whole element would also mask its content). But fine with using <progress> in both cases if you think that's better, no strong opinion either way.

It was also to avoid the block that hides all the prefixed progress-bar and progress-values.

I think that's ok, we'll have a similar issue in slider too.

We could frame the prefixed ones as fallbacks (in the fallbacks section), and only use the actual standard pseudo-elements (::fill, ::track etc) in the main guidance, though that feels a little disingenuous given no browser implements the standard pseudo-elements.

* This could also be a good use case for the new ``accentcolor`` system color keyword once it ships. Does it have a web-feature id? If not, we could use a ``tmp-`` (see #1256)

Hmm, the accentcolor system color keyword is currently part of the system-color web feature, and hidden by a compute_from, so it appears to be widely available. It does appear to be newly available - however, testing and MDN seem to point to it only working in installed PWAs? Is that correct?

There are two components of this:

  1. Is accentcolor supported as a system color keyword, and does it resolve to a reasonable value? (even if not the system one for fingerprinting reasons)
  2. Does it actually resolve to the page accent color if set via the accent-color property?

I think even 1 alone makes it a better fallback than the hardcoded blue we currently have, 2 just improves things further.

They should probably have separate web-feature ids. I'll file an issue in the web-features repo. Meanwhile, that's the textbook case for temporary web-feature ids!

* Even generated content still works in that mode, so progress-ring could be a good use case for expanded ``attr()`` too! Make sure to apply a counter rotate. If that's janky, could switch to no rotate and doing it all in the start and end angles.

This was fairly straightforward to do with attr(),

We do need a MO in the fallback to update it though otherwise the control will fail at this most basic function as a progress bar 😀
See https://github.com/GoogleChrome/modern-web-guidance-src/pull/1371/changes#r3889155946

but I'm not sure what you mean by a "counter rotate".

NVM, there is no content in the indeterminate case and no rotation in the determinate case so this doesn't apply. Also gencontent doesn't work reliably, so just ignore this, sorry!

Visual design

* Another thing that applies to both the progress-ring and the spinner is that we often want rounded line caps. I'm not convinced they matter tremendously in such a small size, but they can be done with ``radial-gradient()`` if need be. Might be worth a note.

I added this as solely a note in the guide, but didn't provide code for this- is that ok?

See https://github.com/GoogleChrome/modern-web-guidance-src/pull/1371/changes#r3889139078

@LeaVerou LeaVerou left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comments. Only critical one is using a MO for the attr() fallback, the rest are mostly suggestions.

Comment thread guides/ui-components/progress-ring/guide.md Outdated
Comment thread guides/ui-components/progress-ring/guide.md
Comment thread guides/ui-components/progress-ring/guide.md Outdated
Comment thread guides/ui-components/progress-ring/guide.md Outdated
Comment thread guides/ui-components/progress-ring/guide.md
Comment thread guides/ui-components/progress-ring/guide.md Outdated
Comment thread guides/ui-components/progress-ring/guide.md Outdated
Comment thread guides/ui-components/progress-ring/guide.md Outdated
Comment thread guides/ui-components/spinner/guide.md Outdated

@LeaVerou LeaVerou left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, see comments and suggestions, but none of them is a blocker.

jamesnw and others added 3 commits August 31, 2026 12:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Create guide and evals for the progress-ring use case

5 participants