# Specular Button

A glass button with a thin lit edge. A WebGL2 highlight sits on the rim. It rests softly on the top-left corner, slides around the edge toward the cursor as the cursor comes near, brightens as it gets closer and flashes when you press. Turn on `auto-animate` to make the light orbit the rim on its own. It renders only while the light moves, so an idle button costs nothing.

<demo-specular-button>



</demo-specular-button>

## Installation

```bash
npx shadcn-vue@latest add "https://nxui.geoql.in/r/specular-button.json"
```

## Usage

```vue
<script setup lang="ts">
  import SpecularButton from '~/components/ui/specular-button/SpecularButton.vue';

  function start() {
    console.log('started');
  }
</script>

<template>
  <SpecularButton
    size="lg"
    :radius="18"
    line-color="#ffffff"
    base-color="#525252"
    :proximity="250"
    @click="start"
  >
    Get Started
  </SpecularButton>
</template>
```

On a light page, use a dark tint (for example `tint="#18181b"` with `:tint-opacity="1"`) and a darker `base-color` such as `#3f3f46`.

## Props

<table>
<thead>
  <tr>
    <th>
      Prop
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Default
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        size
      </code>
    </td>
    
    <td>
      <code>
        'sm' | 'md' | 'lg'
      </code>
    </td>
    
    <td>
      <code>
        'lg'
      </code>
    </td>
    
    <td>
      Padding and font size.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        radius
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        18
      </code>
    </td>
    
    <td>
      Corner radius in pixels. The light follows the same curve.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        tint
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        '#ffffff'
      </code>
    </td>
    
    <td>
      Fill colour of the glass body.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        tint-opacity
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.04
      </code>
    </td>
    
    <td>
      Opacity of the tint (0–1).
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        blur
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0
      </code>
    </td>
    
    <td>
      Backdrop blur in pixels.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        text-color
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        '#f5f5f5'
      </code>
    </td>
    
    <td>
      Label colour.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        line-color
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        '#ffffff'
      </code>
    </td>
    
    <td>
      Colour of the moving highlight. Any CSS colour.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        base-color
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        '#525252'
      </code>
    </td>
    
    <td>
      Colour of the faint resting edge line.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        intensity
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        1
      </code>
    </td>
    
    <td>
      Overall brightness of the highlight.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        idle-intensity
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.35
      </code>
    </td>
    
    <td>
      Brightness while the cursor is far away (0–1).
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        shine-size
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        10
      </code>
    </td>
    
    <td>
      Width of the bright core, in degrees of the rim.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        shine-fade
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        34
      </code>
    </td>
    
    <td>
      Length of the soft falloff around the core, in degrees.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        thickness
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        1.2
      </code>
    </td>
    
    <td>
      Width of the lit edge in pixels.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        glow
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        1
      </code>
    </td>
    
    <td>
      Strength of the soft bloom around the highlight.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        speed
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.35
      </code>
    </td>
    
    <td>
      Orbit speed in radians per second when <code>
        auto-animate
      </code>
      
       is on.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        follow-mouse
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      Steer the highlight toward the cursor.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        proximity
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        250
      </code>
    </td>
    
    <td>
      Distance in pixels at which the cursor starts to pull the light.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        auto-animate
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        false
      </code>
    </td>
    
    <td>
      Orbit the light around the rim; the cursor still takes over.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        disabled
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        false
      </code>
    </td>
    
    <td>
      Disables the button and the cursor tracking.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        type
      </code>
    </td>
    
    <td>
      <code>
        'button' | 'submit' | 'reset'
      </code>
    </td>
    
    <td>
      <code>
        'button'
      </code>
    </td>
    
    <td>
      Native button type.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        class
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        ''
      </code>
    </td>
    
    <td>
      Extra classes for the button.
    </td>
  </tr>
</tbody>
</table>

## Events and slots

<table>
<thead>
  <tr>
    <th>
      API
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        default
      </code>
    </td>
    
    <td>
      Button label. Defaults to "Get Started". Icons may sit inside it.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        @click
      </code>
    </td>
    
    <td>
      Native click on the <code>
        <button>
      </code>
      
       (any native listener falls through).
    </td>
  </tr>
</tbody>
</table>

## Accessibility

- It is a native `<button>`, so Enter, Space, `disabled` and form `type` work as usual.
- The light canvas is `aria-hidden`; the slot text is the accessible name.
- Keyboard focus shows a ring tinted from the text colour.
- With `prefers-reduced-motion: reduce`, `auto-animate` does not orbit and the press scale has no transition. The cursor follow stays, as it moves only on user input.
- Rendering stops while the button is offscreen.
- Ported from [React Bits](https://reactbits.dev/components/specular-button) by David Haz.
