1 Run the shadcn CLI
npx shadcn@latest add https://toggles.dev/r/spin 2 Import and use
import { Spin } from "@/components/ui/spin";
export default function App() {
return <Spin />;
} 1 Install the package
▾
npm install @theme-toggles/react pnpm add @theme-toggles/react yarn add @theme-toggles/react bun add @theme-toggles/react 2 Import and use
import { Spin } from "@theme-toggles/react";
import "@theme-toggles/react/styles/spin.css";
export default function App() {
return <Spin />;
} 1 Copy the component
import { type ButtonHTMLAttributes, type CSSProperties, useId } from "react";
export interface SpinProps extends Omit<
ButtonHTMLAttributes<HTMLButtonElement>,
"children"
> {
duration?: number;
[key: `data-${string}`]: string | number | boolean | null | undefined;
}
export function Spin({
duration = 400,
className,
type = "button",
title = "Toggle theme",
"aria-label": ariaLabel = "Toggle theme",
...props
}: SpinProps) {
const toggleId = useId();
const clipMainId = `toggles.dev-spin-main-${toggleId}`;
return (
<button
type={type}
title={title}
aria-label={ariaLabel}
className={className}
{...props}
>
<svg
width="1em"
height="1em"
viewBox="0 0 24 24"
aria-hidden="true"
style={{ "--toggles-spin--duration": `${duration}ms` } as CSSProperties}
>
<defs>
<clipPath id={clipMainId}>
<path
d={"M0 0h25a1 1 0 0010 10v14H0Z"}
className="transition-[d,translate] duration-(--toggles-spin--duration) dark:delay-[calc(var(--toggles-spin--duration)*0.15)] dark:[d:path('M0_2h13a1_1_0_0010_10v14H0Z')] dark:not-supports-[d:path('M0_0')]:-translate-x-3.25 dark:not-supports-[d:path('M0_0')]:translate-y-0.5"
/>
</clipPath>
</defs>
<g stroke={"currentColor"} strokeLinecap={"round"}>
<circle
cx={12}
cy={12}
r={5}
fill={"currentColor"}
clipPath={`url(#${clipMainId})`}
className="origin-center transition-transform duration-(--toggles-spin--duration) dark:scale-170"
/>
<path
d={"M12 1.4v2.4"}
fill={"none"}
strokeWidth={2}
strokeLinejoin={"round"}
strokeMiterlimit={0}
paintOrder={"stroke markers fill"}
className="origin-center transition-transform duration-(--toggles-spin--duration) delay-[calc(var(--toggles-spin--duration)*0.15)] dark:delay-0 dark:rotate-45 dark:scale-0"
/>
<path
d={"m20.3 3.7-2.5 2.5"}
fill={"none"}
strokeWidth={2}
strokeLinejoin={"round"}
strokeMiterlimit={0}
paintOrder={"stroke markers fill"}
className="origin-center transition-transform duration-(--toggles-spin--duration) delay-[calc(var(--toggles-spin--duration)*0.15)] dark:delay-0 dark:rotate-45 dark:scale-0"
/>
<path
d={"M22.6 12h-2.4"}
fill={"none"}
strokeWidth={2}
strokeLinejoin={"round"}
strokeMiterlimit={0}
paintOrder={"stroke markers fill"}
className="origin-center transition-transform duration-(--toggles-spin--duration) delay-[calc(var(--toggles-spin--duration)*0.15)] dark:delay-0 dark:rotate-45 dark:scale-0"
/>
<path
d={"M12 22.6v-2.4"}
fill={"none"}
strokeWidth={2}
strokeLinejoin={"round"}
strokeMiterlimit={0}
paintOrder={"stroke markers fill"}
className="origin-center transition-transform duration-(--toggles-spin--duration) delay-[calc(var(--toggles-spin--duration)*0.15)] dark:delay-0 dark:rotate-45 dark:scale-0"
/>
<path
d={"M1.4 12h2.4"}
fill={"none"}
strokeWidth={2}
strokeLinejoin={"round"}
strokeMiterlimit={0}
paintOrder={"stroke markers fill"}
className="origin-center transition-transform duration-(--toggles-spin--duration) delay-[calc(var(--toggles-spin--duration)*0.15)] dark:delay-0 dark:rotate-45 dark:scale-0"
/>
<path
d={"m20.3 20.3-2.5-2.5"}
fill={"none"}
strokeWidth={2}
strokeLinejoin={"round"}
strokeMiterlimit={0}
paintOrder={"stroke markers fill"}
className="origin-center transition-transform duration-(--toggles-spin--duration) delay-[calc(var(--toggles-spin--duration)*0.15)] dark:delay-0 dark:rotate-45 dark:scale-0"
/>
<path
d={"m3.7 20.3 2.5-2.5"}
fill={"none"}
strokeWidth={2}
strokeLinejoin={"round"}
strokeMiterlimit={0}
paintOrder={"stroke markers fill"}
className="origin-center transition-transform duration-(--toggles-spin--duration) delay-[calc(var(--toggles-spin--duration)*0.15)] dark:delay-0 dark:rotate-45 dark:scale-0"
/>
<path
d={"m3.7 3.7 2.5 2.5"}
fill={"none"}
strokeWidth={2}
strokeLinejoin={"round"}
strokeMiterlimit={0}
paintOrder={"stroke markers fill"}
className="origin-center transition-transform duration-(--toggles-spin--duration) delay-[calc(var(--toggles-spin--duration)*0.15)] dark:delay-0 dark:rotate-45 dark:scale-0"
/>
</g>
</svg>
</button>
);
} 1 Install the package
▾
npm install @theme-toggles/svelte pnpm add @theme-toggles/svelte yarn add @theme-toggles/svelte bun add @theme-toggles/svelte 2 Import and use
<script>
import { Spin } from "@theme-toggles/svelte";
import "@theme-toggles/svelte/styles/spin.css";
</script>
<Spin /> 1 Copy the component
<script context="module" lang="ts">
let nextId = 0;
</script>
<script lang="ts">
import type { HTMLButtonAttributes } from "svelte/elements";
interface $$Props extends Omit<HTMLButtonAttributes, "children"> {
duration?: number;
ariaLabel?: string;
class?: string;
}
export let duration = 400;
export let type: HTMLButtonAttributes["type"] = "button";
export let title = "Toggle theme";
export let ariaLabel = "Toggle theme";
let className = "";
export { className as class };
const toggleId = `spin-${++nextId}`;
const clipMainId = `toggles.dev-spin-main-${toggleId}`;
</script>
<button
{type}
{title}
aria-label={ariaLabel}
class={className}
on:click
{...$$restProps}
>
<svg
width="1em"
height="1em"
viewBox="0 0 24 24"
aria-hidden="true"
style={`--toggles-spin--duration: ${duration}ms`}
>
<defs>
<clipPath id={clipMainId}>
<path
d={"M0 0h25a1 1 0 0010 10v14H0Z"}
class={"transition-[d,translate] duration-(--toggles-spin--duration) dark:delay-[calc(var(--toggles-spin--duration)*0.15)] dark:[d:path('M0_2h13a1_1_0_0010_10v14H0Z')] dark:not-supports-[d:path('M0_0')]:-translate-x-3.25 dark:not-supports-[d:path('M0_0')]:translate-y-0.5"}
/>
</clipPath>
</defs>
<g stroke={"currentColor"} stroke-linecap={"round"}>
<circle
cx={12}
cy={12}
r={5}
fill={"currentColor"}
clip-path={`url(#${clipMainId})`}
class={"origin-center transition-transform duration-(--toggles-spin--duration) dark:scale-170"}
/>
<path
d={"M12 1.4v2.4"}
fill={"none"}
stroke-width={2}
stroke-linejoin={"round"}
stroke-miterlimit={0}
paint-order={"stroke markers fill"}
class={"origin-center transition-transform duration-(--toggles-spin--duration) delay-[calc(var(--toggles-spin--duration)*0.15)] dark:delay-0 dark:rotate-45 dark:scale-0"}
/>
<path
d={"m20.3 3.7-2.5 2.5"}
fill={"none"}
stroke-width={2}
stroke-linejoin={"round"}
stroke-miterlimit={0}
paint-order={"stroke markers fill"}
class={"origin-center transition-transform duration-(--toggles-spin--duration) delay-[calc(var(--toggles-spin--duration)*0.15)] dark:delay-0 dark:rotate-45 dark:scale-0"}
/>
<path
d={"M22.6 12h-2.4"}
fill={"none"}
stroke-width={2}
stroke-linejoin={"round"}
stroke-miterlimit={0}
paint-order={"stroke markers fill"}
class={"origin-center transition-transform duration-(--toggles-spin--duration) delay-[calc(var(--toggles-spin--duration)*0.15)] dark:delay-0 dark:rotate-45 dark:scale-0"}
/>
<path
d={"M12 22.6v-2.4"}
fill={"none"}
stroke-width={2}
stroke-linejoin={"round"}
stroke-miterlimit={0}
paint-order={"stroke markers fill"}
class={"origin-center transition-transform duration-(--toggles-spin--duration) delay-[calc(var(--toggles-spin--duration)*0.15)] dark:delay-0 dark:rotate-45 dark:scale-0"}
/>
<path
d={"M1.4 12h2.4"}
fill={"none"}
stroke-width={2}
stroke-linejoin={"round"}
stroke-miterlimit={0}
paint-order={"stroke markers fill"}
class={"origin-center transition-transform duration-(--toggles-spin--duration) delay-[calc(var(--toggles-spin--duration)*0.15)] dark:delay-0 dark:rotate-45 dark:scale-0"}
/>
<path
d={"m20.3 20.3-2.5-2.5"}
fill={"none"}
stroke-width={2}
stroke-linejoin={"round"}
stroke-miterlimit={0}
paint-order={"stroke markers fill"}
class={"origin-center transition-transform duration-(--toggles-spin--duration) delay-[calc(var(--toggles-spin--duration)*0.15)] dark:delay-0 dark:rotate-45 dark:scale-0"}
/>
<path
d={"m3.7 20.3 2.5-2.5"}
fill={"none"}
stroke-width={2}
stroke-linejoin={"round"}
stroke-miterlimit={0}
paint-order={"stroke markers fill"}
class={"origin-center transition-transform duration-(--toggles-spin--duration) delay-[calc(var(--toggles-spin--duration)*0.15)] dark:delay-0 dark:rotate-45 dark:scale-0"}
/>
<path
d={"m3.7 3.7 2.5 2.5"}
fill={"none"}
stroke-width={2}
stroke-linejoin={"round"}
stroke-miterlimit={0}
paint-order={"stroke markers fill"}
class={"origin-center transition-transform duration-(--toggles-spin--duration) delay-[calc(var(--toggles-spin--duration)*0.15)] dark:delay-0 dark:rotate-45 dark:scale-0"}
/>
</g>
</svg>
</button> 1 Install the package
▾
npm install @theme-toggles/vue pnpm add @theme-toggles/vue yarn add @theme-toggles/vue bun add @theme-toggles/vue 2 Import and use
<script setup lang="ts">
import { Spin } from "@theme-toggles/vue";
import "@theme-toggles/vue/styles/spin.css";
</script>
<template>
<Spin />
</template> 1 Copy the component
<script lang="ts">
let nextId = 0;
</script>
<script setup lang="ts">
import { useAttrs } from "vue";
interface Props {
duration?: number;
type?: "button" | "submit" | "reset";
title?: string;
ariaLabel?: string;
}
const props = withDefaults(defineProps<Props>(), {
duration: 400,
type: "button",
title: "Toggle theme",
ariaLabel: "Toggle theme",
});
const attrs = useAttrs();
const toggleId = `spin-${++nextId}`;
const clipMainId = `toggles.dev-spin-main-${toggleId}`;
</script>
<template>
<button
v-bind="attrs"
:type="props.type"
:title="props.title"
:aria-label="props.ariaLabel"
>
<svg
width="1em"
height="1em"
viewBox="0 0 24 24"
aria-hidden="true"
:style="{ '--toggles-spin--duration': `${props.duration}ms` }"
>
<defs>
<clipPath :id="clipMainId">
<path
:d="'M0 0h25a1 1 0 0010 10v14H0Z'"
:class="'transition-[d,translate] duration-(--toggles-spin--duration) dark:delay-[calc(var(--toggles-spin--duration)*0.15)] dark:[d:path(\'M0_2h13a1_1_0_0010_10v14H0Z\')] dark:not-supports-[d:path(\'M0_0\')]:-translate-x-3.25 dark:not-supports-[d:path(\'M0_0\')]:translate-y-0.5'"
/>
</clipPath>
</defs>
<g :stroke="'currentColor'" :stroke-linecap="'round'">
<circle
:cx="12"
:cy="12"
:r="5"
:fill="'currentColor'"
:clip-path="`url(#${clipMainId})`"
:class="'origin-center transition-transform duration-(--toggles-spin--duration) dark:scale-170'"
/>
<path
:d="'M12 1.4v2.4'"
:fill="'none'"
:stroke-width="2"
:stroke-linejoin="'round'"
:stroke-miterlimit="0"
:paint-order="'stroke markers fill'"
:class="'origin-center transition-transform duration-(--toggles-spin--duration) delay-[calc(var(--toggles-spin--duration)*0.15)] dark:delay-0 dark:rotate-45 dark:scale-0'"
/>
<path
:d="'m20.3 3.7-2.5 2.5'"
:fill="'none'"
:stroke-width="2"
:stroke-linejoin="'round'"
:stroke-miterlimit="0"
:paint-order="'stroke markers fill'"
:class="'origin-center transition-transform duration-(--toggles-spin--duration) delay-[calc(var(--toggles-spin--duration)*0.15)] dark:delay-0 dark:rotate-45 dark:scale-0'"
/>
<path
:d="'M22.6 12h-2.4'"
:fill="'none'"
:stroke-width="2"
:stroke-linejoin="'round'"
:stroke-miterlimit="0"
:paint-order="'stroke markers fill'"
:class="'origin-center transition-transform duration-(--toggles-spin--duration) delay-[calc(var(--toggles-spin--duration)*0.15)] dark:delay-0 dark:rotate-45 dark:scale-0'"
/>
<path
:d="'M12 22.6v-2.4'"
:fill="'none'"
:stroke-width="2"
:stroke-linejoin="'round'"
:stroke-miterlimit="0"
:paint-order="'stroke markers fill'"
:class="'origin-center transition-transform duration-(--toggles-spin--duration) delay-[calc(var(--toggles-spin--duration)*0.15)] dark:delay-0 dark:rotate-45 dark:scale-0'"
/>
<path
:d="'M1.4 12h2.4'"
:fill="'none'"
:stroke-width="2"
:stroke-linejoin="'round'"
:stroke-miterlimit="0"
:paint-order="'stroke markers fill'"
:class="'origin-center transition-transform duration-(--toggles-spin--duration) delay-[calc(var(--toggles-spin--duration)*0.15)] dark:delay-0 dark:rotate-45 dark:scale-0'"
/>
<path
:d="'m20.3 20.3-2.5-2.5'"
:fill="'none'"
:stroke-width="2"
:stroke-linejoin="'round'"
:stroke-miterlimit="0"
:paint-order="'stroke markers fill'"
:class="'origin-center transition-transform duration-(--toggles-spin--duration) delay-[calc(var(--toggles-spin--duration)*0.15)] dark:delay-0 dark:rotate-45 dark:scale-0'"
/>
<path
:d="'m3.7 20.3 2.5-2.5'"
:fill="'none'"
:stroke-width="2"
:stroke-linejoin="'round'"
:stroke-miterlimit="0"
:paint-order="'stroke markers fill'"
:class="'origin-center transition-transform duration-(--toggles-spin--duration) delay-[calc(var(--toggles-spin--duration)*0.15)] dark:delay-0 dark:rotate-45 dark:scale-0'"
/>
<path
:d="'m3.7 3.7 2.5 2.5'"
:fill="'none'"
:stroke-width="2"
:stroke-linejoin="'round'"
:stroke-miterlimit="0"
:paint-order="'stroke markers fill'"
:class="'origin-center transition-transform duration-(--toggles-spin--duration) delay-[calc(var(--toggles-spin--duration)*0.15)] dark:delay-0 dark:rotate-45 dark:scale-0'"
/>
</g>
</svg>
</button>
</template>