Yesterday we “vibe coded” a counter component with the @elementsbot here on the forum.
I spent a little extra time today tidying it up and making it more usable. In the project (included below) I also set up a couple of Templates to make it even easier to add to your own projects ![]()
Open this Project in Elements and watch the video below to see how it all works ![]()
Oh, and here’s the final code that you can copy and paste into a custom component (if you want to build it yourself):
Template Code:
<div
class=""
x-data="{ count: 0, hasAnimated: false }"
x-intersect.once="if (!hasAnimated) { hasAnimated = true; $nextTick(() => { let start = 0; let end = +{{myNumber}}; let duration = 1500; let startTime = null; function animate(now) { if(!startTime) startTime = now; let progress = Math.min((now - startTime) / duration, 1); count = Math.floor(progress * (end - start) + start); if(progress < 1){ requestAnimationFrame(animate); } } requestAnimationFrame(animate); }); }"
>
@if(edit)
<div class="font-bold {{textColor}} {{headingTextStyles}} {{fontFamily}}">{{myNumber}}</div>
@else
<div class="font-bold {{textColor}} {{headingTextStyles}} {{fontFamily}}" x-text="count"></div>
@endif
</div>
Properties Code:
{
"groups": [
{
"title": "General",
"icon": "gearshape",
"properties": [
{
"title": "Number",
"id": "myNumber",
"number": {
"default": 100
}
},
{
"title": "Font",
"id": "fontFamily",
"themeFont": {
"default": {
"base": { "name": "body" }
}
}
},
{
"title": "Size",
"id": "headingTextStyles",
"themeTextStyle": {
"default": {
"base": {
"name": "5xl"
}
}
}
},
{
"title": "Color",
"id": "textColor",
"format": "text-{{value}}",
"themeColor": {
"default": {
"name": "text",
"brightness": 300
}
}
}
]
}
]
}
