Toggle Count
Free · MITHeadless, accessible, and styled entirely through the attribute surface below — bring your own CSS system, or start from the reference theme.
Install
Without a flag you get no styling at all — plain HTML carrying the attribute surface below. --theme copies the same theme in two dialects;--bridge lumos re-points either one onto Lumos for Astro's tokens (it needs a theme to re-point, and Lumos itself, already in your project).
Unstyled — behavior only, you write the CSS
npx astrocraft-ui add forms/toggle-countPlain-CSS theme — no build step
npx astrocraft-ui add forms/toggle-count --theme cssTailwind theme — needs Tailwind v4
npx astrocraft-ui add forms/toggle-count --theme tailwindPlain-CSS theme, re-pointed onto Lumos tokens
npx astrocraft-ui add forms/toggle-count --theme css --bridge lumosTailwind theme, re-pointed onto Lumos tokens
npx astrocraft-ui add forms/toggle-count --theme tailwind --bridge lumosLive demo
Toggle Count
$19 per month
Attribute surface
With no class-merging machinery, these attributes are the whole extension point. State is a data-attribute or a native attribute; visibility is the hiddenattribute. Generated from source by pnpm slots.
| Component | Slots | Variants | Runtime state | Native state |
|---|---|---|---|---|
| `ToggleCount.astro` | `toggle-count` `toggle-count-off` `toggle-count-on` | — | `data-checked` | — |
| `ToggleCountValue.astro` | `toggle-count-value` | — | — | — |
Source
What the command copies — 3 files, alias-free so the copy lands standing alone. This is the whole component; there is nothing else.
---
// src/components/ui/forms/toggle-count/ToggleCount.astro — headless primitive (see ../../README.md).
// A two-value toggle (e.g. Monthly / Annual pricing) built on the Switch primitive.
// Every <ToggleCountValue for={id}> on the page swaps between its `min` (off) and `max` (on) text when
// this toggle flips — wired by the small bundled script. `id` links the toggle to its values. The two
// side labels are plain text (only the switch is interactive, so a label can't fight the toggle).
import type { HTMLAttributes } from "astro/types";
import Switch from "../../forms/switch";
type Props = HTMLAttributes<"div"> & { id: string; offLabel?: string; onLabel?: string };
const { id, offLabel = "Monthly", onLabel = "Annual", class: className, ...rest } = Astro.props;
---
<div
class={className}
data-slot="toggle-count"
data-toggle-count-id={id}
data-checked="false"
{...rest}
>
<span data-slot="toggle-count-off">{offLabel}</span>
<Switch id={id} aria-label={`Toggle between ${offLabel} and ${onLabel}`} />
<span data-slot="toggle-count-on">{onLabel}</span>
</div>
<script>
import { onReadyOnce } from "../../_once";
function wire(root: HTMLElement) {
const input = root.querySelector<HTMLInputElement>('input[type="checkbox"]');
const id = root.dataset.toggleCountId;
if (!input || !id) return;
const values = document.querySelectorAll<HTMLElement>(
`[data-slot="toggle-count-value"][data-toggle-count="${id}"]`,
);
const sync = () => {
const checked = input.checked;
values.forEach((el) => {
el.textContent = (checked ? el.dataset.max : el.dataset.min) ?? "";
});
root.dataset.checked = String(checked);
};
input.addEventListener("change", sync);
sync();
}
onReadyOnce('[data-slot="toggle-count"]', wire);
</script>
---
// src/components/ui/forms/toggle-count/ToggleCountValue.astro — ToggleCount compound part (see ../../README.md).
// A value that swaps between `min` (toggle off) and `max` (toggle on). `for` must match the linked
// ToggleCount's `id`. Renders `min` by default so it's correct before hydration.
import type { HTMLAttributes } from "astro/types";
type Props = HTMLAttributes<"span"> & { for: string; min: string | number; max: string | number };
const { for: target, min, max, class: className, ...rest } = Astro.props;
---
<span
data-slot="toggle-count-value"
data-toggle-count={target}
data-min={String(min)}
data-max={String(max)}
class={className}
{...rest}>{String(min)}</span
>
import ToggleCount from "./ToggleCount.astro";
import ToggleCountValue from "./ToggleCountValue.astro";
export { ToggleCount, ToggleCountValue };
export default ToggleCount;
What you get
The component source, copied into your project by npx astrocraft-ui add forms/toggle-count — no package dependency, no CSS to fight. Whatever the paid blocks compose, this is it.