Skip to content

Progress

Shimmer

Bit.BlazorUISkeleton

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

A shimmer with nothing set is a single rounded bar that takes the full width of its container and the height of its Size, with the wave sweeping across it. That is the whole component: everything else on this page shapes it, stacks it, retimes it or fills it in.

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.


Height

Width

Shape

Shape is what the placeholder is drawn as, and the point of it is to look like the thing it is waiting for: Rounded (default) for a line of text or a block of content, Square for an image that meets its container edge to edge, Pill for a button, a tag or a chip, and Circle for an avatar or a round icon.

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".


Rounded (default)

Square

Pill

Circle

Radius

Shape carries the three corners a placeholder usually wants, and Radius is for the one it does not: a card, a thumbnail or a control whose corner the theme has no name for. It takes any CSS length, it wins over the shape wherever both are set, and a circle is round by construction so it ignores it.

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.


Radius="0.25rem"

Radius="1rem"

Radius="0" (over a Pill, which it wins over)

Lines

Lines stacks the shimmer into a paragraph: each line takes the single-line Height, the lines are separated by Gap, and the last one is shortened to LastLineWidth - 60% by default, because the last line of a paragraph rarely reaches the end of its measure, which is most of what makes a stack of bars read as text rather than as a table. Set LastLineWidth="100%" for a stack of even rows, and note that a circle is a single shape rather than a stack, so it ignores the count.

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.


Lines="3" (default gap and last line)

Custom gap and last line

Even rows

A measure per line

Animation

Animation is how the placeholder tells the reader that something is still on its way. Wave (default) sweeps a band of the highlight color across the box and turns around on a right-to-left page; Pulse breathes between full and reduced opacity, which is cheaper to paint and calmer on a page carrying many placeholders at once; Fade takes that breath all the way out; and None leaves a static block, which is the right answer for a very long list or a page that already shows a progress indicator of its own - and having no animated part, it is painted in Background alone. Pulse="true" stays as the short spelling of Animation="BitShimmerAnimation.Pulse".

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.


Wave (default)

Pulse

Fade

None

Duration and Delay

Stagger

ShowDelay & MinShowTime

A response that arrives in a few hundred milliseconds turns a placeholder into a flash of grey that is worse than no placeholder at all. ShowDelay holds the shimmer back for that long, so a fast call finishes without one ever being seen while a slow call still gets the placeholder it needs. The wait is held in CSS rather than in a timer, so it costs no render and works under static server-side rendering.

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.



Without ShowDelay
The response is in.

ShowDelay="1000"
The response is in.

ShowDelay="1000" MinShowTime="1000"
The response is in.

Inline

A shimmer is a block by default and takes the full width of its container, which is what a placeholder standing in for a paragraph or a card wants. Inline lays it out in the flow of a line of text instead, so a single value that is still loading can hold its place in a sentence. An inline shimmer takes the width it is given and falls back to the minimum width of a control without one, and a Height of 1em keeps it exactly as tall as the type it sits in whatever that type turns out to be.

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

Loaded is the switch between the placeholder and the real thing: the two are never on the page at the same time, and the content fades in as it replaces the shimmer. The content is ChildContent, or Content under the same name as a template parameter.

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

A placeholder normally stands in for content that is not there yet, so the box it draws is a guess at the size of what is coming. Overlay is the other case: the content is already on the page and is being refreshed, its size is therefore known, and the shimmer is laid over it rather than in place of it. The content stays in the layout - out of sight, out of the tab order and out of reach of a screen reader - so nothing moves when the placeholder goes away.

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.


Overlay
Monthly revenue

$48,120

Up 12% on the previous month.

In place, for comparison

Template

Anything more than a bar, a circle or a stack of lines is drawn as a Template: a layout of shimmers of its own, each with its own shape and size, arranged the way the content will be. The template replaces the placeholder entirely, so the shape, the line count and the animation of the outer shimmer no longer apply - but ShowDelay still does, which holds the whole skeleton back as one rather than letting its parts appear separately.




Accessibility

A placeholder is a visual stand-in and says nothing on its own, so the shimmer marks itself aria-busy while it waits and hides its empty boxes from assistive technologies - a card built from a dozen of them is not read out as a dozen empty groups.

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.


Loading your profile

Background

Background is the resting color of the placeholder - the box the animation plays over - while Color is the color of the animated part itself. Keep the two close together: a placeholder is not content, and a high-contrast pair reads as something the page is actually showing.

A placeholder with no animation has no animated part, so this is the whole of what it is painted in.


Primary

Secondary

Tertiary

Info

Success

Warning

SevereWarning

Error

PrimaryBackground

SecondaryBackground (default)

TertiaryBackground

PrimaryForeground

SecondaryForeground

TertiaryForeground

PrimaryBorder

SecondaryBorder

TertiaryBorder

Color

Color paints the animated part of the shimmer - the wave band, or the block the pulse and the fade play on - in any of the general colors of bit BlazorUI, over the resting Background of the placeholder. A placeholder with no animation has no animated part, so this no longer applies to it.


Primary

Secondary

Tertiary

Info

Success

Warning

SevereWarning

Error

PrimaryBackground

SecondaryBackground

TertiaryBackground (default)

PrimaryForeground

SecondaryForeground

TertiaryForeground

PrimaryBorder

SecondaryBorder

TertiaryBorder

Size

Size is the default height of a line and the default diameter of a circle, so a placeholder can be scaled to the type around it without a length being written out. An explicit Height or Width always wins over it.


Small

Medium (default)

Large

Style & Class

Empower customization by overriding default styles and classes, allowing tailored design modifications to suit specific UI requirements. Style and Class reach the root element, while Styles and Classes reach each part of the component by name - the root, the wrapper of every line, the animated part inside it, the content that replaces them - or that they cover - and the live region that speaks for them.

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.


Component's Style & Class:






Styles & Classes:



RTL

Use Dir="BitDir.Rtl" to render the shimmer in a right-to-left layout. The wave sweeps with the reading direction, so it comes in from the right, and a stack of lines shortens its last one from the right as well.



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.