Skip to content

Timeline

<quiet-timeline> stable since 5.0

Displays a sequence of events, steps, or milestones in a visual timeline.

Timelines display a sequence of events, steps, or milestones in a visual format. Each item has a circular bullet connected by lines to indicate progression. Use the active attribute to highlight the current step, and customize bullets with icons, avatars, spinners, and more.

Your order was placed successfully
We're preparing your items for shipment
Your package will be picked up by the carrier
Package will arrive at your doorstep
<quiet-timeline active="2" id="timeline__overview">
  <quiet-timeline-item label="Order placed">
    <quiet-icon slot="bullet" name="shopping-bag"></quiet-icon>
    Your order was placed successfully<br>
    <time>3 hours ago</time>
  </quiet-timeline-item>

  <quiet-timeline-item label="Processing">
    <quiet-icon slot="bullet" name="package"></quiet-icon>
    We're preparing your items for shipment<br>
    <time>2 hours ago</time>
  </quiet-timeline-item>

  <quiet-timeline-item label="Shipped">
    <quiet-icon slot="bullet" name="truck"></quiet-icon>
    Your package will be picked up by the carrier<br>
    <time>Estimated tomorrow</time>
  </quiet-timeline-item>

  <quiet-timeline-item label="Delivered">
    <quiet-icon slot="bullet" name="check"></quiet-icon>
    Package will arrive at your doorstep<br>
    <time>Estimated in 2–3 days</time>
  </quiet-timeline-item>
</quiet-timeline>

<style>
  #timeline__overview {
    time {
      color: var(--quiet-text-body);
    }
  }
</style>

Examples Jump to heading

Basic usage Jump to heading

Set the active attribute on the timeline to a 1-based index to indicate the current step. The active item receives a primary-colored bullet, and items before it are connected by lines.

Fill out the adoption application Meet your potential new cat Complete the home check Bring your new friend home
<quiet-timeline active="3">
  <quiet-timeline-item label="Step 1">
    Fill out the adoption application
  </quiet-timeline-item>

  <quiet-timeline-item label="Step 2">
    Meet your potential new cat
  </quiet-timeline-item>

  <quiet-timeline-item label="Step 3">
    Complete the home check
  </quiet-timeline-item>

  <quiet-timeline-item label="Step 4">
    Bring your new friend home
  </quiet-timeline-item>
</quiet-timeline>

When no active attribute is set, all bullets appear in the neutral color and no lines are shown.

Tiny paws, endless energy Peak hunting skills and slow blinks Distinguished naps in sunbeams
<quiet-timeline>
  <quiet-timeline-item label="Kitten">
    Tiny paws, endless energy
  </quiet-timeline-item>

  <quiet-timeline-item label="Adult">
    Peak hunting skills and slow blinks
  </quiet-timeline-item>

  <quiet-timeline-item label="Senior">
    Distinguished naps in sunbeams
  </quiet-timeline-item>
</quiet-timeline>

Using the label slot Jump to heading

For labels that require HTML, use the label slot instead of the label attribute.

First Item Done This step has been completed Second Item Pending Currently in progress Waiting to start
<quiet-timeline active="2">
  <quiet-timeline-item>
    <span slot="label">
      First Item <quiet-badge variant="constructive">Done</quiet-badge>
    </span>
    This step has been completed
  </quiet-timeline-item>

  <quiet-timeline-item>
    <span slot="label">
      Second Item <quiet-badge>Pending</quiet-badge>
    </span>
    Currently in progress
  </quiet-timeline-item>

  <quiet-timeline-item label="Third Item">
    Waiting to start
  </quiet-timeline-item>
</quiet-timeline>

Custom bullets Jump to heading

Use the bullet slot to customize bullets with text, icons, or other content. When the slot has content, the bullet's border is replaced with a solid background for visibility and so slotted content can fill the entire space.

1 Gather project requirements 2 Create wireframes and mockups 3 Build and test the feature Deploying to production…
<quiet-timeline active="3" id="timeline__numbered">
  <quiet-timeline-item label="Requirements">
    <span slot="bullet">1</span>
    Gather project requirements
  </quiet-timeline-item>

  <quiet-timeline-item label="Design">
    <span slot="bullet">2</span>
    Create wireframes and mockups
  </quiet-timeline-item>

  <quiet-timeline-item label="Development">
    <span slot="bullet">3</span>
    Build and test the feature
  </quiet-timeline-item>

  <quiet-timeline-item label="Launch">
    <quiet-spinner slot="bullet"></quiet-spinner>
    Deploying to production…
  </quiet-timeline-item>
</quiet-timeline>

<style>
  #timeline__numbered [slot="bullet"] {
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.75em;
    font-weight: var(--quiet-font-weight-semibold);
  }
</style>

Icons are drawn over a solid background for visibility.

A new furry friend arrives Vaccinations and a clean bill of health Officially runs the household 3 AM, right on schedule
<quiet-timeline active="3">
  <quiet-timeline-item label="Brought home">
    <quiet-icon slot="bullet" name="home" style="font-size: 0.75em;"></quiet-icon>
    A new furry friend arrives
  </quiet-timeline-item>

  <quiet-timeline-item label="First vet visit">
    <quiet-icon slot="bullet" name="stethoscope" style="font-size: 0.75em;"></quiet-icon>
    Vaccinations and a clean bill of health
  </quiet-timeline-item>

  <quiet-timeline-item label="Claimed the couch">
    <quiet-icon slot="bullet" name="armchair" style="font-size: 0.75em;"></quiet-icon>
    Officially runs the household
  </quiet-timeline-item>

  <quiet-timeline-item label="First zoomies">
    <quiet-icon slot="bullet" name="bolt" style="font-size: 0.75em;"></quiet-icon>
    3 AM, right on schedule
  </quiet-timeline-item>
</quiet-timeline>

You can also use avatars and spinners as bullets. Remember that avatars can contain identicons and monsters too.

Showed zero remorse Sniffed the evidence, walked away Unbothered, as usual Someone has to pick up the pieces
<quiet-timeline active="2">
  <quiet-timeline-item label="Whiskers knocked over the vase" style="--line-color: #027bcb;">
    <quiet-avatar slot="bullet" label="Shadow" image="https://images.unsplash.com/photo-1574158622682-e40e69881006?q=80&w=256&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"></quiet-avatar>
    Showed zero remorse
  </quiet-timeline-item>

  <quiet-timeline-item label="Mittens investigated the scene" line-variant="dashed">
    <quiet-avatar slot="bullet" label="Mittens">
      <quiet-identicon slot="icon" value="mittens@example.com" pixel-size="3" cols="7" rows="7"></quiet-identicon>
    </quiet-avatar>
    Sniffed the evidence, walked away
  </quiet-timeline-item>

  <quiet-timeline-item label="Shadow took a nap">
    <quiet-avatar slot="bullet" label="Shadow">
      <quiet-monster slot="icon" value="shadow@example.com"></quiet-monster>
    </quiet-avatar>
    Unbothered, as usual
  </quiet-timeline-item>

  <quiet-timeline-item label="Cleanup in progress">
    <quiet-spinner slot="bullet"></quiet-spinner>
    Someone has to pick up the pieces
  </quiet-timeline-item>
</quiet-timeline>

Custom spacing Jump to heading

Adjust the --spacing custom property to control the distance between timeline items.


Less space between items Adjustable layout Drag the slider to adjust
<div id="timeline__spacing">
  <quiet-slider
    label="Spacing"
    min="0"
    max="3"
    step="0.25"
    value="0.75"
    with-tooltip
    style="max-width: 360px; margin-block-end: 1.5rem;"
  ></quiet-slider>

  <br>

  <quiet-timeline active="2" style="--spacing: 0.75em;">
    <quiet-timeline-item label="Compact">
      Less space between items
    </quiet-timeline-item>

    <quiet-timeline-item label="Timeline">
      Adjustable layout
    </quiet-timeline-item>

    <quiet-timeline-item label="Items">
      Drag the slider to adjust
    </quiet-timeline-item>
  </quiet-timeline>
</div>

<script>
  const spacingContainer = document.getElementById('timeline__spacing');
  const spacingSlider = spacingContainer.querySelector('quiet-slider');
  const spacingTimeline = spacingContainer.querySelector('quiet-timeline');
  const emFormatter = new Intl.NumberFormat('en-US', { minimumFractionDigits: 0, maximumFractionDigits: 2 });

  customElements.whenDefined('quiet-slider').then(() => {
    spacingSlider.valueFormatter = value => `${emFormatter.format(value)} em`;
  });

  spacingSlider.addEventListener('quiet-input', () => {
    spacingTimeline.style.setProperty('--spacing', `${spacingSlider.value}em`);
  });
</script>

Changing the size Jump to heading

Timelines are sized relative to the current font size. To change the overall size, apply font-size to the timeline or an ancestor element.


Sized with font-size Drag the slider to adjust Everything scales together
<div id="timeline__size">
  <quiet-slider
    label="Font size"
    min="0.75"
    max="1.5"
    step="0.05"
    value="1"
    with-tooltip
    style="max-width: 360px; margin-block-end: 1.5rem;"
  ></quiet-slider>

  <br>

  <quiet-timeline active="2" style="font-size: 1rem;">
    <quiet-timeline-item label="Scalable">
      Sized with font-size
    </quiet-timeline-item>

    <quiet-timeline-item label="Timeline">
      Drag the slider to adjust
    </quiet-timeline-item>

    <quiet-timeline-item label="Items">
      Everything scales together
    </quiet-timeline-item>
  </quiet-timeline>
</div>

<script>
  const sizeContainer = document.getElementById('timeline__size');
  const sizeSlider = sizeContainer.querySelector('quiet-slider');
  const sizeTimeline = sizeContainer.querySelector('quiet-timeline');
  const remFormatter = new Intl.NumberFormat('en-US', { minimumFractionDigits: 0, maximumFractionDigits: 2 });

  customElements.whenDefined('quiet-slider').then(() => {
    sizeSlider.valueFormatter = value => `${remFormatter.format(value)} rem`;
  });

  sizeSlider.addEventListener('quiet-input', () => {
    sizeTimeline.style.fontSize = `${sizeSlider.value}rem`;
  });
</script>

Changing the placement Jump to heading

Set placement="end" to position the timeline's bullets and lines at the opposite end of the content. Text will also be aligned to the end.

Breakfast demands at 6 AM Extended nap on the warm laptop Bird watching from the windowsill Surprise zoomies across the house
<quiet-timeline active="2" placement="end">
  <quiet-timeline-item label="Morning">
    Breakfast demands at 6 AM
  </quiet-timeline-item>

  <quiet-timeline-item label="Midday">
    Extended nap on the warm laptop
  </quiet-timeline-item>

  <quiet-timeline-item label="Afternoon">
    Bird watching from the windowsill
  </quiet-timeline-item>

  <quiet-timeline-item label="Evening">
    Surprise zoomies across the house
  </quiet-timeline-item>
</quiet-timeline>

Alternating items Jump to heading

Add the alternate attribute to alternate content on either side of the bullet line, creating a centered zigzag layout.

Wake up and stretch Demand food immediately Find the sunniest spot Race through the house at top speed
<quiet-timeline active="3" alternate>
  <quiet-timeline-item label="Morning">
    <quiet-icon slot="bullet" name="sun" style="font-size: 0.75em;"></quiet-icon>
    Wake up and stretch
  </quiet-timeline-item>

  <quiet-timeline-item label="Breakfast">
    <quiet-icon slot="bullet" name="bowl" style="font-size: 0.75em;"></quiet-icon>
    Demand food immediately
  </quiet-timeline-item>

  <quiet-timeline-item label="Nap time">
    <quiet-icon slot="bullet" name="moon" style="font-size: 0.75em;"></quiet-icon>
    Find the sunniest spot
  </quiet-timeline-item>

  <quiet-timeline-item label="Zoomies">
    <quiet-icon slot="bullet" name="bolt" style="font-size: 0.75em;"></quiet-icon>
    Race through the house at top speed
  </quiet-timeline-item>
</quiet-timeline>

Reversing the timeline Jump to heading

When the timeline needs to show the most recent event first, use the reverse attribute. This will cause the flow of completion to reverse, starting at the last item instead of the first.

Found a forever home Temporary care with a loving family Picked up from the street Spotted hiding under a porch
<quiet-timeline active="3" reverse>
  <quiet-timeline-item label="Adopted">
    Found a forever home
  </quiet-timeline-item>

  <quiet-timeline-item label="Fostered">
    Temporary care with a loving family
  </quiet-timeline-item>

  <quiet-timeline-item label="Rescued">
    Picked up from the street
  </quiet-timeline-item>

  <quiet-timeline-item label="Found">
    Spotted hiding under a porch
  </quiet-timeline-item>
</quiet-timeline>

Dashed and dotted lines Jump to heading

Set line-variant on individual timeline items to change their connecting line to dashed or dotted. This is useful for indicating uncertain or pending steps.

You've chosen a new companion Home check passed with flying colors Final vaccinations in progress Ready for pickup this weekend
<quiet-timeline active="2">
  <quiet-timeline-item label="Cat selected">
    You've chosen a new companion
  </quiet-timeline-item>

  <quiet-timeline-item label="Application approved">
    Home check passed with flying colors
  </quiet-timeline-item>

  <quiet-timeline-item label="Preparing to leave" line-variant="dashed">
    Final vaccinations in progress
  </quiet-timeline-item>

  <quiet-timeline-item label="Homecoming">
    Ready for pickup this weekend
  </quiet-timeline-item>
</quiet-timeline>

You can also use dotted for a different look.

Brushed and looking fresh Awaiting lab results Healthy and happy
<quiet-timeline active="2">
  <quiet-timeline-item label="Grooming">
    Brushed and looking fresh
  </quiet-timeline-item>

  <quiet-timeline-item label="Vet check" line-variant="dotted">
    Awaiting lab results
  </quiet-timeline-item>

  <quiet-timeline-item label="All clear">
    Healthy and happy
  </quiet-timeline-item>
</quiet-timeline>

Custom indicator colors Jump to heading

Use the --bullet-color and --line-color custom properties on individual timeline items to override the bullet and line colors when active or completed. The line-variant attribute can also be set to dashed, dotted, or solid for each item.

All 42 tests passed 3 warnings found Error in compilation step Waiting for build to pass
<quiet-timeline active="3">
  <quiet-timeline-item label="Tests passed" style="--bullet-color: var(--quiet-constructive-fill-mid); --line-color: var(--quiet-constructive-fill-mid);">
    <quiet-icon slot="bullet" name="check" style="font-size: 0.75em;"></quiet-icon>
    All 42 tests passed
  </quiet-timeline-item>

  <quiet-timeline-item label="Lint warnings" style="--bullet-color: var(--quiet-caution-fill-mid); --line-color: var(--quiet-caution-fill-mid);">
    <quiet-icon slot="bullet" name="alert-triangle" style="font-size: 0.75em;"></quiet-icon>
    3 warnings found
  </quiet-timeline-item>

  <quiet-timeline-item label="Build failed" style="--bullet-color: var(--quiet-destructive-fill-mid);" line-variant="dashed">
    <quiet-icon slot="bullet" name="x" style="font-size: 0.75em;"></quiet-icon>
    Error in compilation step
  </quiet-timeline-item>

  <quiet-timeline-item label="Deploy" style="--bullet-color: var(--quiet-neutral-fill-mid);">
    <quiet-spinner slot="bullet"></quiet-spinner>
    Waiting for build to pass
  </quiet-timeline-item>
</quiet-timeline>

Styling the timeline Jump to heading

Use CSS parts to customize the appearance of individual elements within the timeline.

A spark of inspiration Put it down on paper Make it real Ship it and party!
<quiet-timeline active="3" alternate id="timeline__styled">
  <quiet-timeline-item label="Idea" line-variant="dashed">
    <quiet-icon slot="bullet" name="bulb"></quiet-icon>
    A spark of inspiration
  </quiet-timeline-item>

  <quiet-timeline-item label="Sketch" line-variant="dashed">
    <quiet-icon slot="bullet" name="pencil"></quiet-icon>
    Put it down on paper
  </quiet-timeline-item>

  <quiet-timeline-item label="Build" line-variant="dotted">
    <quiet-icon slot="bullet" name="hammer"></quiet-icon>
    Make it real
  </quiet-timeline-item>

  <quiet-timeline-item label="Celebrate">
    <quiet-icon slot="bullet" name="confetti"></quiet-icon>
    Ship it and party!
  </quiet-timeline-item>
</quiet-timeline>

<style>
  #timeline__styled {
    --bullet-size: 2rem;

    quiet-timeline-item {
      &::part(bullet) {
        border-radius: 0.75rem;
        corner-shape: squircle;
        background-color: var(--color);
        color: var(--text-color);
      }

      &::part(body) {
        max-width: 200px;
        margin-block-start: -0.625rem;
        padding: 0.625rem 0.875rem;
        border-radius: 0.75rem;
        background: linear-gradient(135deg, color-mix(in oklab, var(--color) 20%, transparent), color-mix(in oklab, var(--color) 8%, transparent));
        border: 1px solid color-mix(in oklab, var(--color) 25%, transparent);
        color: var(--text-color);
      }

      &::part(label) {
        font-size: 0.875rem;
        color: color-mix(in oklab, var(--text-color) 100%, black 10%);
        line-height: 1.4;
      }

      &::part(content) {
        font-size: 0.75rem;
        color: inherit;
      }

      &:nth-child(1) {
        --color: #fbbf24;
        --text-color: #78350f;
      }

      &:nth-child(2) {
        --color: #f0abfc;
        --text-color: #86198f;
      }

      &:nth-child(3) {
        --color: #6ee7b7;
        --text-color: #064e3b;
      }

      &:nth-child(4) {
        --color: #7dd3fc;
        --text-color: #0c4a6e;
      }

      .quiet-dark & {
        &:nth-child(1) {
          --color: #92400e;
          --text-color: #fde68a;
        }

        &:nth-child(2) {
          --color: #701a75;
          --text-color: #f5d0fe;
        }

        &:nth-child(3) {
          --color: #065f46;
          --text-color: #a7f3d0;
        }

        &:nth-child(4) {
          --color: #0c4a6e;
          --text-color: #bae6fd;
        }
      }

      &:nth-child(1):state(completed)::part(line) {
        background: linear-gradient(to bottom, #fbbf24, #f0abfc);
      }

      &:nth-child(2):state(completed)::part(line) {
        background: linear-gradient(to bottom, #f0abfc, #6ee7b7);
      }

      .quiet-dark &:nth-child(1):state(completed)::part(line) {
        background: linear-gradient(to bottom, #92400e, #701a75);
      }

      .quiet-dark &:nth-child(2):state(completed)::part(line) {
        background: linear-gradient(to bottom, #701a75, #065f46);
      }
    }
  }
</style>

Here's another example that uses small bullets to create a compact activity feed.

Whiskers merged PR #42 Mittens opened an issue "Food dish low"
<quiet-timeline active="3" id="timeline__activity">
  <quiet-timeline-item style="--bullet-color: #16a34a;">
    <span slot="label">Whiskers merged <a href="#">PR #42</a></span>
    <time>12 min ago</time>
  </quiet-timeline-item>

  <quiet-timeline-item style="--bullet-color: #2563eb;">
    <span slot="label">
      Mittens opened an issue <a href="#">"Food dish low"</a>
    </span>
    <time>45 min ago</time>
  </quiet-timeline-item>

  <quiet-timeline-item label="Shadow deployed to staging" style="--bullet-color: #9333ea;">
    <time>2 hours ago</time>
  </quiet-timeline-item>

  <quiet-timeline-item label="Patches updated the roadmap" style="--bullet-color: #ea580c;">
    <time>4 hours ago</time>
  </quiet-timeline-item>
</quiet-timeline>

<style>
  #timeline__activity {
    --bullet-size: 0.5rem;
    --line-width: 1px;
    --line-color: var(--quiet-neutral-stroke-softer);
    --spacing: 1em;

    quiet-timeline-item::part(bullet) {
      border: none;
      background-color: var(--bullet-color, var(--quiet-neutral-stroke-softer));
    }

    quiet-timeline-item::part(label) {
      font-weight: var(--quiet-font-weight-semibold);
      margin-block-end: .5rem;
    }
  }
</style>

API Jump to heading

Importing Jump to heading

The autoloader is the recommended way to import components but, if you prefer to do it manually, the following code snippets will be helpful.

CDN Self-hosted

To manually import <quiet-timeline> from the CDN, use the following code.

import 'https://cdn.quietui.org/v5.0.0/components/timeline/timeline.js';

To manually import <quiet-timeline> from a self-hosted distribution, use the following code. Remember to replace /path/to/quiet with the appropriate local path.

import '/path/to/quiet/components/timeline/timeline.js';

Slots Jump to heading

Timeline supports the following slots. Learn more about using slots

Name Description
(default) One or more <quiet-timeline-item> elements.

Properties Jump to heading

Timeline has the following properties that can be set with corresponding attributes. In many cases, the attribute's name is the same as the property's name. If an attribute is different, it will be displayed after the property. Learn more about attributes and properties

Property Description Reflects Type Default
active The 1-based index of the active timeline item. The active item receives a primary-colored bullet. number
placement Where the bullets and lines are placed relative to the content. 'start'
'end'
'start'
alternate When set, content alternates on either side of the bullet line. boolean false
reverse When set, items after the active item are marked as completed instead of items before it. boolean false

CSS custom properties Jump to heading

Timeline supports the following CSS custom properties. You can style them like any other CSS property. Learn more about CSS custom properties

Name Description Default
--spacing The amount of space between timeline items. 2em
--bullet-size The size of each timeline item's bullet. 1.5em
--line-width The width of the lines and bullet borders. 0.1875em

Dependencies Jump to heading

Timeline automatically imports the following elements. Sub-dependencies are also included in this list.

Search this website Toggle dark mode View the code on GitHub Follow @quietui.org on Bluesky Follow @quiet_ui on X

    No results found