Buttons buttonshimmerelegant

Shimmer Button

A highly elegant button with a moving shimmer outline.

Preview

Usage

Copy the full block below to use this component with its imports.

astro
---
import { ShimmerButton } from 'astro-component-kit';
---

<ShimmerButton href="#" type="button" variant="primary" size="md" disabled={false}>Unlock Premium</ShimmerButton>
--- import { ShimmerButton } from 'astro-component-kit'; --- <ShimmerButton href="#" type="button" variant="primary" size="md" disabled={false}>Unlock Premium</ShimmerButton>

Manual Installation

If you are not using the npm package, create a new file src/components/lib/ShimmerButton.astro and paste the following code:

astro
---
interface Props {
  href?: string;
  type?: 'button' | 'submit' | 'reset';
  variant?: 'primary' | 'secondary' | 'ghost';
  size?: 'sm' | 'md' | 'lg';
  disabled?: boolean;
}

const { 
  href, 
  type = 'button', 
  variant = 'primary', 
  size = 'md',
  disabled = false 
} = Astro.props;

const Tag = href ? 'a' : 'button';
---

<Tag 
  href={href} 
  type={href ? undefined : type}
  disabled={disabled}
  class={`shimmer-btn shimmer-btn--${variant} shimmer-btn--${size}`}
>
  <span class="shimmer-btn__content"><slot /></span>
</Tag>

<style>
  .shimmer-btn {
    --shimmer-speed: 3s;
    --shimmer-color: rgba(255, 255, 255, 0.3);
    
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: none;
    border-radius: var(--r-full, 9999px);
    cursor: pointer;
    text-decoration: none;
    overflow: hidden;
    transition: all 0.3s ease;
    user-select: none;
    font-family: var(--font-sans, inherit);
    font-weight: 600;
    white-space: nowrap;
  }

  .shimmer-btn__content {
    display: block;
    padding: 0.75rem 1.8rem;
    z-index: 2;
  }

  .shimmer-btn::after {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(
      120deg, 
      transparent 30%, 
      var(--shimmer-color) 50%, 
      transparent 70%
    );
    background-size: 200% 100%;
    transform: translateX(-100%);
    animation: sweep var(--shimmer-speed) infinite;
    z-index: 1;
  }

  @keyframes sweep {
    0% { transform: translateX(-100%); }
    40%, 100% { transform: translateX(100%); }
  }

  .shimmer-btn:hover:not(:disabled) {
    transform: scale(1.02);
  }

  .shimmer-btn:disabled {
    opacity: 0.5;
    cursor: not-allowed;
    filter: grayscale(1);
  }

  /* Variants */
  .shimmer-btn--primary {
    background: var(--c-bg-2, #1e293b);
    color: #fff;
    border: 1px solid rgba(255, 255, 255, 0.1);
  }

  .shimmer-btn--secondary {
    background: var(--c-primary, #6366f1);
    color: #fff;
  }

  .shimmer-btn--ghost {
    background: transparent;
    color: var(--c-primary-light, #818cf8);
    border: 1px solid rgba(99, 102, 241, 0.4);
    --shimmer-color: rgba(99, 102, 241, 0.2);
  }

  /* Sizes */
  .shimmer-btn--sm .shimmer-btn__content { padding: 0.45rem 1.2rem; font-size: 0.8rem; }
  .shimmer-btn--md .shimmer-btn__content { padding: 0.75rem 1.8rem; font-size: 0.95rem; }
  .shimmer-btn--lg .shimmer-btn__content { padding: 1.1rem 2.6rem; font-size: 1.1rem; }
</style>
--- interface Props { href?: string; type?: 'button' | 'submit' | 'reset'; variant?: 'primary' | 'secondary' | 'ghost'; size?: 'sm' | 'md' | 'lg'; disabled?: boolean; } const { href, type = 'button', variant = 'primary', size = 'md', disabled = false } = Astro.props; const Tag = href ? 'a' : 'button'; --- <Tag href={href} type={href ? undefined : type} disabled={disabled} class={`shimmer-btn shimmer-btn--${variant} shimmer-btn--${size}`} > <span class="shimmer-btn__content"><slot /></span> </Tag> <style> .shimmer-btn { --shimmer-speed: 3s; --shimmer-color: rgba(255, 255, 255, 0.3); position: relative; display: inline-flex; align-items: center; justify-content: center; padding: 0; border: none; border-radius: var(--r-full, 9999px); cursor: pointer; text-decoration: none; overflow: hidden; transition: all 0.3s ease; user-select: none; font-family: var(--font-sans, inherit); font-weight: 600; white-space: nowrap; } .shimmer-btn__content { display: block; padding: 0.75rem 1.8rem; z-index: 2; } .shimmer-btn::after { content: ""; position: absolute; inset: 0; background: linear-gradient( 120deg, transparent 30%, var(--shimmer-color) 50%, transparent 70% ); background-size: 200% 100%; transform: translateX(-100%); animation: sweep var(--shimmer-speed) infinite; z-index: 1; } @keyframes sweep { 0% { transform: translateX(-100%); } 40%, 100% { transform: translateX(100%); } } .shimmer-btn:hover:not(:disabled) { transform: scale(1.02); } .shimmer-btn:disabled { opacity: 0.5; cursor: not-allowed; filter: grayscale(1); } /* Variants */ .shimmer-btn--primary { background: var(--c-bg-2, #1e293b); color: #fff; border: 1px solid rgba(255, 255, 255, 0.1); } .shimmer-btn--secondary { background: var(--c-primary, #6366f1); color: #fff; } .shimmer-btn--ghost { background: transparent; color: var(--c-primary-light, #818cf8); border: 1px solid rgba(99, 102, 241, 0.4); --shimmer-color: rgba(99, 102, 241, 0.2); } /* Sizes */ .shimmer-btn--sm .shimmer-btn__content { padding: 0.45rem 1.2rem; font-size: 0.8rem; } .shimmer-btn--md .shimmer-btn__content { padding: 0.75rem 1.8rem; font-size: 0.95rem; } .shimmer-btn--lg .shimmer-btn__content { padding: 1.1rem 2.6rem; font-size: 1.1rem; } </style>

Quick Info

Category
Buttons
Filename
ShimmerButton.astro
Dependencies
None — pure Astro + CSS
Tags
buttonshimmerelegant