Free
a month
Month to month
- 3 sites
- 10K renders a month
- 250 MB of storage
All components · Category: Pricing and counters
Monthly and yearly plans with prices that roll like an odometer.
Plan cards under a switch: flip it and every price rolls digit by digit to the other period, with the saving worked out from your own numbers. The plans, prices and limits all come from props, so the page decides every figure. It has no payment step, and choosing a plan only tells your page.
01
Props
Generated from the component's manifest and the values above.
index.html
<pricing-toggle
currency="$"
period="yearly"
locale="en"
plans="[{"name":"Free","monthly":0,"yearly":0,"limits":"3 sites;10K renders a month;250 MB of storage","featured":false},{"name":"Pro","monthly":14,"yearly":140,"limits":"25 sites;1.25M renders a month;3 GB of storage","featured":true},{"name":"Agency","monthly":49,"yearly":490,"limits":"100 sites;4M renders a month;50 GB of storage","featured":false}]"
></pricing-toggle>
<script>
const element = document.querySelector("pricing-toggle");
element.addEventListener("pricing-toggle:period", (event) => {
console.log(event.detail);
});
element.addEventListener("pricing-toggle:pick", (event) => {
console.log(event.detail);
});
</script>
taggor-component.js
const element = document.createElement("pricing-toggle");
element.setAttribute("currency", "$");
element.setAttribute("period", "yearly");
element.setAttribute("locale", "en");
element.plans = [
{
"name": "Free",
"monthly": 0,
"yearly": 0,
"limits": "3 sites;10K renders a month;250 MB of storage",
"featured": false
},
{
"name": "Pro",
"monthly": 14,
"yearly": 140,
"limits": "25 sites;1.25M renders a month;3 GB of storage",
"featured": true
},
{
"name": "Agency",
"monthly": 49,
"yearly": 490,
"limits": "100 sites;4M renders a month;50 GB of storage",
"featured": false
}
];
element.addEventListener("pricing-toggle:period", (event) => {
console.log(event.detail);
});
element.addEventListener("pricing-toggle:pick", (event) => {
console.log(event.detail);
});
document.body.append(element);
PricingToggle.tsx
import { useEffect, useRef } from "react";
export function PricingToggle() {
const ref = useRef<HTMLElement>(null);
useEffect(() => {
const element = ref.current;
if (!element) return;
Object.assign(element, {
plans: [
{
"name": "Free",
"monthly": 0,
"yearly": 0,
"limits": "3 sites;10K renders a month;250 MB of storage",
"featured": false
},
{
"name": "Pro",
"monthly": 14,
"yearly": 140,
"limits": "25 sites;1.25M renders a month;3 GB of storage",
"featured": true
},
{
"name": "Agency",
"monthly": 49,
"yearly": 490,
"limits": "100 sites;4M renders a month;50 GB of storage",
"featured": false
}
],
});
const onPeriod = (event: Event) => {
console.log((event as CustomEvent).detail);
};
element.addEventListener("pricing-toggle:period", onPeriod);
const onPick = (event: Event) => {
console.log((event as CustomEvent).detail);
};
element.addEventListener("pricing-toggle:pick", onPick);
return () => {
element.removeEventListener("pricing-toggle:period", onPeriod);
element.removeEventListener("pricing-toggle:pick", onPick);
};
}, []);
return <pricing-toggle ref={ref} currency={"$"} period="yearly" locale="en" />;
}
PricingToggle.tsx
import { useEffect, useRef } from "react";
export function PricingToggle() {
const ref = useRef<HTMLElement>(null);
useEffect(() => {
const element = ref.current;
if (!element) return;
Object.assign(element, {
plans: [
{
"name": "Free",
"monthly": 0,
"yearly": 0,
"limits": "3 sites;10K renders a month;250 MB of storage",
"featured": false
},
{
"name": "Pro",
"monthly": 14,
"yearly": 140,
"limits": "25 sites;1.25M renders a month;3 GB of storage",
"featured": true
},
{
"name": "Agency",
"monthly": 49,
"yearly": 490,
"limits": "100 sites;4M renders a month;50 GB of storage",
"featured": false
}
],
});
const onPeriod = (event: Event) => {
console.log((event as CustomEvent).detail);
};
element.addEventListener("pricing-toggle:period", onPeriod);
const onPick = (event: Event) => {
console.log((event as CustomEvent).detail);
};
element.addEventListener("pricing-toggle:pick", onPick);
return () => {
element.removeEventListener("pricing-toggle:period", onPeriod);
element.removeEventListener("pricing-toggle:pick", onPick);
};
}, []);
return <pricing-toggle ref={ref} currency={"$"} period="yearly" locale="en" />;
}
src/PricingToggle.vue
<script setup lang="ts">
function onPeriod(event: Event) {
console.log((event as CustomEvent).detail);
}
function onPick(event: Event) {
console.log((event as CustomEvent).detail);
}
</script>
<template>
<pricing-toggle
currency="$"
period="yearly"
locale="en"
:plans.prop="[{"name":"Free","monthly":0,"yearly":0,"limits":"3 sites;10K renders a month;250 MB of storage","featured":false},{"name":"Pro","monthly":14,"yearly":140,"limits":"25 sites;1.25M renders a month;3 GB of storage","featured":true},{"name":"Agency","monthly":49,"yearly":490,"limits":"100 sites;4M renders a month;50 GB of storage","featured":false}]"
@pricing-toggle:period="onPeriod"
@pricing-toggle:pick="onPick"
/>
</template>
vite.config.ts
import vue from "@vitejs/plugin-vue";
import { defineConfig } from "vite";
export default defineConfig({
plugins: [
vue({
template: {
compilerOptions: {
isCustomElement: (tag) => tag === "pricing-toggle",
},
},
}),
],
});
src/app/pricing-toggle.component.ts
import { afterNextRender, Component, CUSTOM_ELEMENTS_SCHEMA, DestroyRef, ElementRef, inject } from "@angular/core";
@Component({
selector: "app-pricing-toggle",
schemas: [CUSTOM_ELEMENTS_SCHEMA],
template: `
<pricing-toggle
[currency]="'$'"
period="yearly"
locale="en"
[plans]="values.plans"
></pricing-toggle>
`,
})
export class PricingToggleComponent {
readonly values = {
plans: [
{
"name": "Free",
"monthly": 0,
"yearly": 0,
"limits": "3 sites;10K renders a month;250 MB of storage",
"featured": false
},
{
"name": "Pro",
"monthly": 14,
"yearly": 140,
"limits": "25 sites;1.25M renders a month;3 GB of storage",
"featured": true
},
{
"name": "Agency",
"monthly": 49,
"yearly": 490,
"limits": "100 sites;4M renders a month;50 GB of storage",
"featured": false
}
],
};
constructor() {
const host = inject<ElementRef<HTMLElement>>(ElementRef);
const element = () => host.nativeElement.querySelector("pricing-toggle");
const onPeriod = (event: Event) => {
console.log((event as CustomEvent).detail);
};
afterNextRender(() => element()?.addEventListener("pricing-toggle:period", onPeriod));
inject(DestroyRef).onDestroy(() => element()?.removeEventListener("pricing-toggle:period", onPeriod));
const onPick = (event: Event) => {
console.log((event as CustomEvent).detail);
};
afterNextRender(() => element()?.addEventListener("pricing-toggle:pick", onPick));
inject(DestroyRef).onDestroy(() => element()?.removeEventListener("pricing-toggle:pick", onPick));
}
}
src/TaggorComponent.svelte
<script>
function onPeriod(event) {
console.log(event.detail);
}
function onPick(event) {
console.log(event.detail);
}
</script>
<pricing-toggle
currency={"$"}
period="yearly"
locale="en"
plans={[
{
"name": "Free",
"monthly": 0,
"yearly": 0,
"limits": "3 sites;10K renders a month;250 MB of storage",
"featured": false
},
{
"name": "Pro",
"monthly": 14,
"yearly": 140,
"limits": "25 sites;1.25M renders a month;3 GB of storage",
"featured": true
},
{
"name": "Agency",
"monthly": 49,
"yearly": 490,
"limits": "100 sites;4M renders a month;50 GB of storage",
"featured": false
}
]}
onpricing-toggle:period={onPeriod}
onpricing-toggle:pick={onPick}
></pricing-toggle>
How an agent gets a component like this onto a site:
taggor checktaggor publishThe CSS variables the component exposes, set the way a customer's page would.
styles.css
pricing-toggle {
--pt-radius: 18px;
}02
| Prop | Type | Default | What it does |
|---|---|---|---|
| plans | list | none | The plans. Prices are numbers (yearly is the whole year's total); limits are separated by semicolons. |
| currency | string | $ | Symbol before each price. |
| period | monthly | yearly | yearly | Which period the switch starts on. |
| cta | string | none | Replaces the plan button text. |
| hideSample | boolean | false | Hides the Sample content mark (use it with your own plans). |
| locale | pt-BR | en | en | – |
Prop names and descriptions are the component's own, in English, as its author wrote them.
03
| Event | When it fires |
|---|---|
| period | The visitor moved the switch. |
| pick | The visitor chose a plan. |
04
Paste this into your agent. It asks you before it signs in, pays or goes further than checking and publishing.
Build me a Taggor component like "Pricing toggle" (pricing-toggle): Monthly and yearly plans with prices that roll like an odometer.
Fetch https://taggor.dev/agent-setup/prompt.md and follow its instructions to set me up for Taggor. Ask me before you sign in, create an account, accept terms, pay for anything or type a secret.
Check it with `taggor check` and publish it with `taggor publish`, and stop there.
Do not promote it to production, attach it to a site, roll back anything or use --yes, --force or --force-drop-invalid unless I ask for exactly that in this conversation.
05