Odometer
A Web Component that displays a numeric value with a smooth rolling animation — similar to a mechanical odometer or number counter. It’s designed for use in badges, notifications, dashboards, or any place where numbers change dynamically.
Code
<bl-odometer></bl-odometer>
<div class="btn-group" role="group">
<button
class="btn blue-btn-soft-secondary"
onclick="this.parentNode.previousElementSibling.value--"
aria-label="Decrement"
>
➖
</button>
<button
class="btn blue-btn-soft-secondary"
onclick="this.parentNode.previousElementSibling.value++"
aria-label="Increment"
>
➕
</button>
</div> Styled as badge
Code
<button type="button" class="btn btn-outline-primary">
<span aria-hidden="true">🔔</span> Notifications
<span class="badge bg-primary-subtle text-primary-emphasis">
<bl-odometer value="2"></bl-odometer>
</span>
</button>
<div class="btn-group" role="group">
<button
class="btn blue-btn-soft-secondary"
onclick="this.parentNode.previousElementSibling.querySelector('bl-odometer').value--"
aria-label="Decrement"
>
➖
</button>
<button
class="btn blue-btn-soft-secondary"
onclick="this.parentNode.previousElementSibling.querySelector('bl-odometer').value++"
aria-label="Increment"
>
➕
</button>
</div> Custom max number
Code
<bl-odometer value="89" max="99"></bl-odometer>
<div class="btn-group" role="group">
<button
class="btn blue-btn-soft-secondary"
onclick="this.parentNode.previousElementSibling.value--"
aria-label="Decrement"
>
➖
</button>
<button
class="btn blue-btn-soft-secondary"
onclick="this.parentNode.previousElementSibling.value++"
aria-label="Increment"
>
➕
</button>
</div> Style based on change
When the value changes, the element will get attribute data-change="up" or data-change="down" depending on if the number increased or decreased.
This allows you to add styling based on the new state. After 3 seconds the attribute will be reset.
Code
<span class="badge rounded-pill bg-body-tertiary text-body border">
<style>
@scope {
:scope {
transition:
background-color 0.3s,
color 0.4s;
}
:scope:has([data-change="up"]) {
background-color: var(--bs-success-bg-subtle) !important;
color: var(--bs-success-text-emphasis) !important;
border-color: var(--bs-success-bg-subtle) !important;
}
:scope:has([data-change="down"]) {
background-color: var(--bs-danger-bg-subtle) !important;
color: var(--bs-danger-text-emphasis) !important;
border-color: var(--bs-danger-bg-subtle) !important;
}
bl-odometer[data-change="up"]::after {
content: "↑";
}
bl-odometer[data-change="down"]::after {
content: "↓";
}
}
</style>
<bl-odometer></bl-odometer>
</span>
<div class="btn-group" role="group">
<button
class="btn blue-btn-soft-secondary"
onclick="this.parentNode.previousElementSibling.querySelector('bl-odometer').value--"
aria-label="Decrement"
>
➖
</button>
<button
class="btn blue-btn-soft-secondary"
onclick="this.parentNode.previousElementSibling.querySelector('bl-odometer').value++"
aria-label="Increment"
>
➕
</button>
</div> Change transition duration
You can change the duration using CSS variable --bl-odometer-duration. Default value is 0.4s. In this example it is set to 5s:
Code
<bl-odometer style="--bl-odometer-duration: 5s"></bl-odometer>
<div class="btn-group" role="group">
<button
class="btn blue-btn-soft-secondary"
onclick="this.parentNode.previousElementSibling.value--"
aria-label="Decrement"
>
➖
</button>
<button
class="btn blue-btn-soft-secondary"
onclick="this.parentNode.previousElementSibling.value++"
aria-label="Increment"
>
➕
</button>
</div> Grab the code
When you don't use the entire Blue Web library, you can also just copy and paste the required code into your own project.
-
Copy and paste the following code into your project. Source: @/src/js/odometer.ts