# Around Theme Toggle

> An animated sun-and-moon theme toggle with a sweeping transition.

A shadcn/ui block from the [@toggles](https://toggles.dev) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/toggles/around).

- Page, with a live preview: https://shadcn.exchange/r/toggles/around
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/toggles/around-light-ba6b7ffba42660e6.png
- Registry item: https://toggles.dev/r/around.json
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://toggles.dev/r/around.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Files

### `src/Around.tsx`

```tsx
import { type ButtonHTMLAttributes, type CSSProperties, useId } from "react";

export interface AroundProps extends Omit<
  ButtonHTMLAttributes<HTMLButtonElement>,
  "children"
> {
  duration?: number;
  /** Whether the toggle should render in its dark-theme state. */
  toggled?: boolean;
  [key: `data-${string}`]: string | number | boolean | null | undefined;
}

export function Around({
  duration = 500,
  toggled,
  className,
  type = "button",
  title = "Toggle theme",
  "aria-label": ariaLabel = "Toggle theme",
  "aria-pressed": ariaPressed,
  ...props
}: AroundProps) {
  const toggleId = useId();

  const clipMainId = `toggles.dev-around-main-${toggleId}`;

  return (
    <button
      {...props}
      type={type}
      title={title}
      aria-label={ariaLabel}
      aria-pressed={toggled ?? ariaPressed}
      className={[
        className,
        toggled === true ? "dark" : toggled === false ? "light" : undefined,
      ]
        .filter(Boolean)
        .join(" ")}
    >
      <svg
        width="1em"
        height="1em"
        viewBox="0 0 32 32"
        aria-hidden="true"
        fill={"currentColor"}
        style={
          { "--toggles-around--duration": `${duration}ms` } as CSSProperties
        }
      >
        <defs>
          <clipPath
            id={clipMainId}
            className="[transform-origin:center] motion-safe:[transition:transform_calc(var(--toggles-around--duration)_*_0.6)_ease] dark:[transform:rotate(-90deg)] motion-safe:dark:[transition:transform_var(--toggles-around--duration)_ease]"
          >
            <path
              d={"M0 0h42v30a1 1 0 00-16 13H0Z"}
              className="motion-safe:transition-[d,translate] motion-safe:[transition-duration:calc(var(--toggles-around--duration)_*_0.6)] motion-safe:[transition-timing-function:ease] dark:[d:path('M-12_-14h42v30a1_1_0_00-16_13H0Z')] dark:not-supports-[d:path('M0_0')]:-translate-x-[12px] dark:not-supports-[d:path('M0_0')]:-translate-y-[14px] motion-safe:dark:[transition-duration:var(--toggles-around--duration)]"
            />
          </clipPath>
        </defs>
        <g clipPath={`url(#${clipMainId})`}>
          <circle
            cx={16}
            cy={16}
            r={8.4}
            className="[transform-origin:center] motion-safe:[transition:transform_calc(var(--toggles-around--duration)_*_0.6)_ease] dark:[transform:scale(1.4)] motion-safe:dark:[transition:transform_var(--toggles-around--duration)_ease]"
          />
          <g>
            <circle
              cx={16}
              cy={3.3}
              r={2.3}
              className="[transform-origin:center] motion-safe:[transition:transform_calc(var(--toggles-around--duration)_*_0.2)_ease_calc(var(--toggles-around--duration)_*_0.253)] dark:[transform:scale(0)] motion-safe:dark:[transition:transform_calc(var(--toggles-around--duration)_*_0.4)_ease]"
            />
            <circle
              cx={27}
              cy={9.7}
              r={2.3}
              className="[transform-origin:center] motion-safe:[transition:transform_calc(var(--toggles-around--duration)_*_0.2)_ease_calc(var(--toggles-around--duration)_*_0.348)] dark:[transform:scale(0)] motion-safe:dark:[transition:transform_calc(var(--toggles-around--duration)_*_0.4)_ease]"
            />
            <circle
              cx={27}
              cy={22.3}
              r={2.3}
              className="[transform-origin:center] motion-safe:[transition:transform_calc(var(--toggles-around--duration)_*_0.2)_ease_calc(var(--toggles-around--duration)_*_0.443)] dark:[transform:scale(0)] motion-safe:dark:[transition:transform_calc(var(--toggles-around--duration)_*_0.4)_ease]"
            />
            <circle
              cx={16}
              cy={28.7}
              r={2.3}
              className="[transform-origin:center] motion-safe:[transition:transform_calc(var(--toggles-around--duration)_*_0.2)_ease_calc(var(--toggles-around--duration)_*_0.538)] dark:[transform:scale(0)] motion-safe:dark:[transition:transform_calc(var(--toggles-around--duration)_*_0.4)_ease]"
            />
            <circle
              cx={5}
              cy={22.3}
              r={2.3}
              className="[transform-origin:center] motion-safe:[transition:transform_calc(var(--toggles-around--duration)_*_0.2)_ease_calc(var(--toggles-around--duration)_*_0.633)] dark:[transform:scale(0)] motion-safe:dark:[transition:transform_calc(var(--toggles-around--duration)_*_0.4)_ease]"
            />
            <circle
              cx={5}
              cy={9.7}
              r={2.3}
              className="[transform-origin:center] motion-safe:[transition:transform_calc(var(--toggles-around--duration)_*_0.2)_ease_calc(var(--toggles-around--duration)_*_0.728)] dark:[transform:scale(0)] motion-safe:dark:[transition:transform_calc(var(--toggles-around--duration)_*_0.4)_ease]"
            />
          </g>
        </g>
      </svg>
    </button>
  );
}
```
