# Within Theme Toggle

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

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

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

## Install

```bash
npx shadcn@latest add https://toggles.dev/r/within.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/Within.tsx`

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

export interface WithinProps 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 Within({
  duration = 500,
  toggled,
  className,
  type = "button",
  title = "Toggle theme",
  "aria-label": ariaLabel = "Toggle theme",
  "aria-pressed": ariaPressed,
  ...props
}: WithinProps) {
  const toggleId = useId();

  const clipMainId = `toggles.dev-within-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-within--duration": `${duration}ms` } as CSSProperties
        }
      >
        <defs>
          <clipPath id={clipMainId}>
            <path d={"M0 0h32v32h-32ZM6 16A1 1 0 0026 16 1 1 0 006 16"} />
          </clipPath>
        </defs>
        <g clipPath={`url(#${clipMainId})`}>
          <path
            d={
              "M30.7 21.3 27.1 16l3.7-5.3c.4-.5.1-1.3-.6-1.4l-6.3-1.1-1.1-6.3c-.1-.6-.8-.9-1.4-.6L16 5l-5.4-3.7c-.5-.4-1.3-.1-1.4.6l-1 6.3-6.4 1.1c-.6.1-.9.9-.6 1.3L4.9 16l-3.7 5.3c-.4.5-.1 1.3.6 1.4l6.3 1.1 1.1 6.3c.1.6.8.9 1.4.6l5.3-3.7 5.3 3.7c.5.4 1.3.1 1.4-.6l1.1-6.3 6.3-1.1c.8-.1 1.1-.8.7-1.4zM16 25.1c-5.1 0-9.1-4.1-9.1-9.1 0-5.1 4.1-9.1 9.1-9.1s9.1 4.1 9.1 9.1c0 5.1-4 9.1-9.1 9.1z"
            }
            className="[transform-origin:center] motion-safe:[transition:transform_var(--toggles-within--duration)_cubic-bezier(0,0,0,1.25)] dark:[transform:scale(0.65)]"
          />
        </g>
        <path
          d={
            "M16 7.7c-4.6 0-8.2 3.7-8.2 8.2s3.6 8.4 8.2 8.4 8.2-3.7 8.2-8.2-3.6-8.4-8.2-8.4zm0 14.4c-3.4 0-6.1-2.9-6.1-6.2s2.7-6.1 6.1-6.1c3.4 0 6.1 2.9 6.1 6.2s-2.7 6.1-6.1 6.1z"
          }
          className="[transform-origin:center] motion-safe:[transition:transform_var(--toggles-within--duration)_cubic-bezier(0,0,0,1.25)] dark:[transform:scale(1.5)]"
        />
        <path
          d={
            "M16 9.5c-3.6 0-6.4 2.9-6.4 6.4s2.8 6.5 6.4 6.5 6.4-2.9 6.4-6.4-2.8-6.5-6.4-6.5z"
          }
          className="[transform-origin:center] motion-safe:[transition:transform_var(--toggles-within--duration)_cubic-bezier(0,0,0,1.25)] dark:[transform:translate3d(3px,-3px,0)_scale(1.2)]"
        />
      </svg>
    </button>
  );
}
```
