Progress
Shimmer
Shimmer is a temporary placeholder for content that has not arrived yet, so a page can lay itself out before its data is in rather than blocking on it. It draws a bar, a square, a pill or a circle at any size and corner, stacks itself into a paragraph with a measure per line, and animates with a wave, a pulse, a fade or nothing at all; anything more elaborate is a template of shimmers of its own, and content already on the page is covered rather than stood in for. It holds itself back so a fast response never flashes a placeholder and lingers so one landing just afterwards never flickers, fades into the real content once it is loaded, and carries a live region so a screen reader is told when the wait is over.
Notes
A shimmer is a placeholder for content that has not arrived rather than a signal that work is in progress, so it honors the reduced motion preference of the OS/browser (prefers-reduced-motion) by stopping outright: the wave, the pulse and the fade are taken out and the static block is left behind. If nothing on this page is moving, either turn the reduce motion setting off, use the ForceAnimation parameter, or turn on the ForceAnimation toggle at the top of this page.
Usage
Every example is live. Open its code to see exactly what produced the component running underneath.
Basic
Width and Height take any CSS length. The height sizes the placeholder only - once the content is loaded it decides its own height, so the box never crops what it was standing in for - while the width stays with the component, which keeps a placeholder and the content that replaces it in the same column.
Shape
A circle is as wide as it is tall whichever of the two was given, so Height and Width are interchangeable on it, and Circle="true" stays as the short spelling of Shape="BitShimmerShape.Circle".
Radius
Match it to the corner of the surface the content will be drawn on - a placeholder whose corner disagrees with the card that replaces it is the one part of a skeleton a reader notices.
Lines
LineWidths goes the rest of the way: real prose does not run to the same measure on every line, so this gives each line a measure of its own. It is a prefix rather than a replacement - a line the list does not reach keeps the width it would have had anyway, which is the full measure or the shortened last one - so a two-entry list over four lines only varies the first two.
Animation
Duration is one full sweep or one full breath in milliseconds and Delay is the pause before the first loop; neither applies to None. The animation loops for as long as the placeholder is on the page, so it stops outright - rather than running faster - as soon as the reader asks for reduced motion, which is why this page keeps it still until the animation toggle turns it back on.
Stagger offsets the lines of a stack against one another, so line n starts at Delay + n * Stagger. A stack whose lines all start together reads as one block breathing; a small offset - a tenth of the duration is usually enough - reads as a paragraph arriving line by line.
ShowDelay & MinShowTime
MinShowTime is the other half of the same answer: a response landing just after the placeholder has appeared would take it away in the same breath, which reads as a flicker rather than as loading, so a placeholder that has been seen stays for at least this long. It is measured from the moment the placeholder appears, so the whole wait is at most the delay plus this, and nothing is held back for a placeholder that was never shown.
Press each button and watch the three: the first starts shimmering immediately whatever happens, the second only when the wait is real, and the third also refuses to blink - the middle button is the case the pair is written for. Both time the placeholder rather than its animation, whose pace is Duration and Delay.
Inline
The root is rendered as a span rather than a div while it is inline, so a placeholder standing in the middle of a paragraph is phrasing content and the paragraph stays in one piece.
The plan costs per month and renews on .
Loaded
The sizing of the placeholder goes with it, so the content is laid out by the page rather than by the box that was standing in for it.
Overlay
The cover is one box over the whole of the content, so Lines and Template no longer apply and the size comes from the content rather than from Height. ShowDelay still does, and it holds the content on the page while it waits, so a refresh that returns quickly never blanks the box it was covering.
Monthly revenue
$48,120
Up 12% on the previous month.Template
Accessibility
Label adds the part that has to be spoken: a live region, visible only to assistive technologies, that carries this text while loading and swaps to LoadedLabel once the content arrives. The swap is what gets announced, which is the point - a screen reader user is told the wait is over rather than being left on a silent page. Set it on the one shimmer that stands for a whole region rather than on each of a group of them, and raise Politeness beyond polite only where the content is the reason the reader is on the page.
AriaLabel is the quieter half of the same idea: it names the placeholder without announcing anything. Because aria-label names nothing at all on a plain element, a shimmer that is given one publishes itself as an indeterminate progressbar while it waits - which is what a placeholder standing in for content on its way actually is - and gives the role back once the content is in.
Background
A placeholder with no animation has no animated part, so this is the whole of what it is painted in.
Color
Size
Style & Class
For a color pair outside the general roles, set the resting color as a background-color on the wrapper and the highlight as the --bit-smr-bg-clr custom property on the root - the one value the wave, the pulse and the fade all read - or paint a gradient of your own straight onto the shimmer.
RTL
API
Every parameter, public member, sub-class and enum this component exposes.
BitShimmer parameters
| Name | Type | Default value | Description |
|---|---|---|---|
| Animation | BitShimmerAnimation? | null | The animation the shimmer plays while it stands in for content that has not arrived yet. Duration and Delay retune whichever animation is chosen, and None leaves a static block that neither of them applies to. |
| Background | BitColor? | null | The background color of the container of the shimmer, which is the resting color of the placeholder the animation plays over - and the whole of what a placeholder with no animation is painted in. |
| ChildContent | RenderFragment? | null | The content that will be shown when the Loaded parameter changes to true. |
| Circle | bool | false | Renders the shimmer as circle instead of a rectangle. This is the short spelling of Shape="BitShimmerShape.Circle", which wins over it when both are set. |
| Classes | BitShimmerClassStyles? | null | Custom CSS classes for different parts of the BitShimmer. |
| Color | BitColor? | null | The color of the animated part of the shimmer, over the resting Background of the placeholder. A placeholder with no animation has no animated part, so it no longer applies there. |
| Content | RenderFragment? | null | Alias of ChildContent. |
| Delay | int? | null | The animation delay value in ms, which is the pause before each loop of the animation and not the wait before the placeholder itself appears (that one is ShowDelay). |
| Duration | int? | null | The animation duration value in ms: one full sweep of the wave, or one full breath of the pulse and the fade. |
| Gap | string? | null | The gap between the lines of a multi-line shimmer, as a CSS length. Only applies while Lines is greater than 1, and defaults to the rhythm unit of the theme. |
| Height | string? | null | The shimmer height value. It sizes the placeholder rather than the component, so once Loaded turns true the content decides its own height. With more than one line it is the height of each single line. Left unset, the height comes from Size. |
| Inline | bool | false | Lays the shimmer out in the flow of a line of text instead of as a block of its own, taking the width given by Width and falling back to the minimum control width of the theme. A Height of 1em keeps it exactly as tall as the type it sits in. |
| Label | string? | null | The text announced by assistive technologies while the shimmer is standing in for content. It is carried by a live region that swaps to LoadedLabel once the content arrives, and it is that swap which gets announced. |
| LastLineWidth | string? | null | The width of the last line of a multi-line shimmer, as a CSS length. Only applies while Lines is greater than 1, and defaults to 60% so a stack of bars reads as a paragraph. |
| Lines | int | 1 | The number of placeholder lines rendered as a stack, which is what a paragraph of text reads as. A circle is a single shape rather than a stack, so it ignores this. |
| LineWidths | IList<string>? | null | The width of each line of a multi-line shimmer, as a list of CSS lengths. Only applies while Lines is greater than 1, and it is a prefix rather than a replacement: a line the list does not reach keeps the width it would have had anyway, which is the full measure or the shortened LastLineWidth. |
| Loaded | bool | false | Controls when the shimmer is swapped with actual data through an animated transition. The placeholder and the content are never on the page at the same time, and the sizing of the placeholder is dropped with it. |
| LoadedLabel | string? | null | The text announced by assistive technologies once the content has replaced the shimmer. |
| MinShowTime | int? | null | The shortest time in ms a placeholder that has been seen stays on the page. ShowDelay keeps a fast response from ever showing a placeholder; this keeps a response landing just after one has appeared from taking it away in the same breath, which reads as a flicker rather than as loading. It is measured from the moment the placeholder appears, and nothing is held back for a placeholder that was never shown. |
| Overlay | bool | false | Draws the placeholder over the content instead of in place of it, so the box keeps the size of the thing it is waiting on and the page never reflows as the placeholder is swapped out. The cover is one box over the whole content, so Lines and Template no longer apply and the size comes from the content rather than from Height. |
| Politeness | BitPoliteness | BitPoliteness.Polite | How urgently the live region of the shimmer interrupts a screen reader. Only applies while Label or LoadedLabel is set. |
| Pulse | bool | false | Changes the animation type of the shimmer to pulse. This is the short spelling of Animation="BitShimmerAnimation.Pulse", which wins over it when both are set. |
| Radius | string? | null | The corner radius of the placeholder, as a CSS length. Shape already carries the three radii a placeholder usually wants; this is for the corner that has to match a surface of its own, and it wins over the shape wherever both are set. A circle is round by construction, so it ignores this. |
| Shape | BitShimmerShape? | null | The shape of the placeholder the shimmer draws: a circle for an avatar, a pill for a button or a tag, a square for an image that meets its container edge to edge. |
| ShowDelay | int? | null | The wait in ms before the placeholder appears, so a fast response never flashes a placeholder. The wait is held in CSS rather than in a timer, so it costs no render and works under static server-side rendering. |
| Size | BitSize? | null | The size of the shimmer, which is the height of a line and the diameter of a circle. An explicit Height or Width always wins over it. |
| Stagger | int? | null | The offset in ms between the animation of one line of a multi-line shimmer and the next, added to Delay rather than replacing it: line n starts at Delay + n * Stagger. Only applies while Lines is greater than 1. |
| Styles | BitShimmerClassStyles? | null | Custom CSS styles for different parts of the BitShimmer. |
| Template | RenderFragment? | null | The custom template to replace the default shimmer container and animation. It replaces the placeholder itself, so Shape, Lines, Animation and the sizing parameters no longer apply, while ShowDelay still holds the whole skeleton back as one. |
| Width | string? | null | The shimmer width value. Unlike Height it stays with the component after the swap, so a placeholder and the content that replaces it occupy the same column. |
BitComponentBase parameters
| Name | Type | Default value | Description |
|---|---|---|---|
| AriaLabel | string? | null | Gets or sets the accessible label for the component, used by assistive technologies. |
| Class | string? | null | Gets or sets the CSS class name(s) to apply to the rendered element. |
| Dir | BitDir? | null | Gets or sets the text directionality for the component's content. |
| ForceAnimation | bool | false | Gets or sets a value indicating whether the component's animations play at their full duration even when reduced motion is requested. |
| HtmlAttributes | Dictionary<string, object> | new Dictionary<string, object>() | Captures additional HTML attributes to be applied to the rendered element, in addition to the component's parameters. |
| Id | string? | null | Gets or sets the unique identifier for the component's root element. |
| IsEnabled | bool | true | Gets or sets a value indicating whether the component is enabled and can respond to user interaction. |
| Style | string? | null | Gets or sets the CSS style string to apply to the rendered element. |
| TabIndex | string? | null | Gets or sets the tab order index for the component when navigating with the keyboard. |
| Visibility | BitVisibility | BitVisibility.Visible | Gets or sets the visibility state (visible, hidden, or collapsed) of the component. |
BitComponentBase public members
| Name | Type | Default value | Description |
|---|---|---|---|
| UniqueId | Guid | Guid.NewGuid() | Gets the readonly unique identifier for the component's root element, assigned when the component instance is constructed. |
| RootElement | ElementReference | Gets the reference to the root HTML element associated with this component. |
BitShimmerClassStyles properties
| Name | Type | Default value | Description |
|---|---|---|---|
| Root | string? | null | Custom CSS classes/styles for the root element of the BitShimmer. |
| Content | string? | null | Custom CSS classes/styles for the content of the BitShimmer. The same box holds the content an Overlay covers. |
| Label | string? | null | Custom CSS classes/styles for the live region of the BitShimmer that carries its Label and LoadedLabel. |
| ShimmerWrapper | string? | null | Custom CSS classes/styles for the shimmer wrapper of the BitShimmer. A multi-line shimmer draws one wrapper per line, so these are applied to each of them. |
| Shimmer | string? | null | Custom CSS classes/styles for the shimmer of the BitShimmer, which is the animated part inside each wrapper and is not drawn at all when the animation is None. |
BitShimmerAnimation enum
| Name | Value | Description |
|---|---|---|
| Wave | 0 | A highlight band sweeps across the placeholder from one side to the other, reversing with the direction of the page. |
| Pulse | 1 | The placeholder breathes between full and reduced opacity, which is cheaper to paint than the wave and calmer on a page full of placeholders. |
| Fade | 2 | The placeholder fades all the way out and back in, a heavier version of the pulse for a single placeholder that has to be noticed. |
| None | 3 | No animation at all: the placeholder is a static block of its Background, with no animated part left for Color to paint. |
BitShimmerShape enum
| Name | Value | Description |
|---|---|---|
| Rounded | 0 | A rectangle with the small corner radius of the theme, which is what a line of text or a block of content reads as. |
| Square | 1 | A rectangle with no corner radius at all, for content that meets its container edge to edge. |
| Pill | 2 | A rectangle with fully rounded ends, which is what a button, a tag or a chip reads as. |
| Circle | 3 | A circle, which is what an avatar or a round icon reads as. It takes its diameter from whichever of the height and the width is set, and ignores Lines. |
BitSize enum
| Name | Value | Description |
|---|---|---|
| Small | 0 | The small size shimmer. |
| Medium | 1 | The medium size shimmer. |
| Large | 2 | The large size shimmer. |
BitPoliteness enum
| Name | Value | Description |
|---|---|---|
| Off | 0 | The region is not a live region: nothing in it is announced as it changes. |
| Polite | 1 | The change waits its turn and is announced once the screen reader has finished what it was saying. |
| Assertive | 2 | The change interrupts the screen reader and is announced right away. |
BitColor enum
| Name | Value | Description |
|---|---|---|
| Primary | 0 | Info Primary general color. |
| Secondary | 1 | Secondary general color. |
| Tertiary | 2 | Tertiary general color. |
| Info | 3 | Info general color. |
| Success | 4 | Success general color. |
| Warning | 5 | Warning general color. |
| SevereWarning | 6 | SevereWarning general color. |
| Error | 7 | Error general color. |
| PrimaryBackground | 8 | Primary background color. |
| SecondaryBackground | 9 | Secondary background color. |
| TertiaryBackground | 10 | Tertiary background color. |
| PrimaryForeground | 11 | Primary foreground color. |
| SecondaryForeground | 12 | Secondary foreground color. |
| TertiaryForeground | 13 | Tertiary foreground color. |
| PrimaryBorder | 14 | Primary border color. |
| SecondaryBorder | 15 | Secondary border color. |
| TertiaryBorder | 16 | Tertiary border color. |
BitVisibility enum
| Name | Value | Description |
|---|---|---|
| Visible | 0 | The content of the component is visible. |
| Hidden | 1 | The content of the component is hidden, but the space it takes on the page remains (visibility:hidden). |
| Collapsed | 2 | The component is hidden (display:none). |
BitDir enum
| Name | Value | Description |
|---|---|---|
| Ltr | 0 | Ltr (left to right) is to be used for languages that are written from the left to the right (like English). |
| Rtl | 1 | Rtl (right to left) is to be used for languages that are written from the right to the left (like Arabic). |
| Auto | 2 | Auto lets the user agent decide. It uses a basic algorithm as it parses the characters inside the element until it finds a character with a strong directionality, then applies that directionality to the whole element. |
Feedback
Found a mistake, a gap, or something that could be clearer? Every page and every component is one click from its source.