bottega

primitives

Icon Expand Button

A compact gradient button that expands on hover: resting at scale 0.89 it scales to full size on hover while hidden CSS-anatomy annotation elements — padding indicators, background and border-radius callouts, and decorative dots and curves around the icon — fade and pop in. All annotations are aria-hidden; the always-visible label provides the accessible name. Keyboardable, focus-visible ring, reduced-motion degrades to opacity-only reveal with no scale.

Ported from barisdogansutcu (MIT)


Install

1. Register the namespace (once per project):

json
// components.json — register the @bottega namespace once
{
  "registries": {
    "@bottega": { "url": "https://bottega.ariacode.ca/r/{name}.json" }
  }
}

2. Add the component:

bash
npx shadcn add @bottega/icon-expand-button

Usage

Usagetsx
<IconExpandButton />

Props

PropTypeDefaultDescription
labelstringAnatomyThe visible button label that always provides the accessible name. Default "Anatomy".

Source

icon-expand-button.tsxtsx
"use client";

import type React from "react";
import styles from "./icon-expand-button.module.css";

export interface IconExpandButtonProps extends React.ComponentProps<"button"> {
  /** The visible button label that always provides the accessible name. Default "Anatomy". */
  label?: string;
}

export function IconExpandButton({
  label = "Anatomy",
  className,
  ...props
}: IconExpandButtonProps) {
  return (
    <button
      type="button"
      className={[styles.button, className].filter(Boolean).join(" ")}
      {...props}
    >
      {/* Icon wrapper with decorative ::before dot + ::after curved-line annotation.
          The whole group is aria-hidden because it's decorative anatomy markup. */}
      <div className={styles.icon} aria-hidden="true">
        {/* "Icon" annotation label — in DOM for AT consistency, visually hidden at rest. */}
        <span className={`${styles.textIcon} ${styles.hide}`}>Icon</span>
        {/* Pencil/edit SVG icon — decorative, aria-hidden */}
        <svg
          aria-hidden="true"
          strokeLinejoin="round"
          strokeLinecap="round"
          fill="none"
          strokeWidth="2"
          stroke="currentColor"
          height="20"
          width="20"
          viewBox="0 0 24 24"
        >
          <path d="M17 3a2.828 2.828 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5L17 3z" />
        </svg>
      </div>

      {/* Always-visible label — provides the accessible name for the button */}
      <span className={styles.title}>{label}</span>

      {/* Decorative anatomy annotations — all aria-hidden, reveal on hover */}
      <div className={`${styles.paddingLeft} ${styles.hide}`} aria-hidden="true">
        <div className={styles.paddingLeftLine}>
          <span className={styles.paddingLeftText}>Left Padding</span>
        </div>
      </div>

      <div className={`${styles.paddingRight} ${styles.hide}`} aria-hidden="true">
        <div className={styles.paddingRightLine}>
          <span className={styles.paddingRightText}>Right Padding</span>
        </div>
      </div>

      <div className={`${styles.background} ${styles.hide}`} aria-hidden="true">
        <span className={styles.backgroundText}>Background</span>
      </div>

      <div className={`${styles.border} ${styles.hide}`} aria-hidden="true">
        <span className={styles.borderText}>Border Radius</span>
      </div>
    </button>
  );
}

Dependencies

  • @bottega/tokens