# Magic Bento

> A bento grid of feature cards with live artwork, edge light that follows the cursor and a click wave across the grid.

Six feature cards with animated artwork rise in when the grid scrolls into view. Move the cursor over the grid to light up the card edges and the hovered card; scrub the analytics chart; click a card to send a ring of light across the grid and replay its artwork.

<demo-magic-bento>



</demo-magic-bento>

## Installation

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

## Usage

```vue
<script setup lang="ts">
  import { MagicBento } from '~/components/ui/magic-bento';
  import type { MagicBentoItem } from '~/components/ui/magic-bento';

  const items: MagicBentoItem[] = [
    {
      label: 'Insights',
      title: 'Analytics',
      icon: 'lucide:chart-line',
      visual: 'analytics',
    },
    {
      title: 'The Pier',
      description: 'Dusk',
      image: '/pier.webp',
      colSpan: 2,
      rowSpan: 2,
    },
    { title: 'Uptime', description: 'Last 90 days', visual: 'uptime' },
    { title: 'Docs', description: 'Read the guide', href: '/docs' },
  ];

  function onItemClick(item: MagicBentoItem, index: number) {
    console.log(item.title, index);
  }
</script>

<template>
  <MagicBento
    :items="items"
    theme="dark"
    glow-color="#38bdf8"
    enable-stars
    @item-click="onItemClick"
  >
    <!-- Custom artwork for any item whose `visual` is not a built-in name -->
    <template #uptime>
      <div class="h-full rounded-lg bg-emerald-500/20" />
    </template>
  </MagicBento>
</template>
```

Built-in artwork: `analytics` (scrubbable line chart), `dashboard` (bar chart), `collaboration` (live document with two cursors), `automation` (CI pipeline that runs when you hover), `integration` (app hub with packets) and `security` (SSO / 2FA switches).

## Props

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

<tbody>
  <tr>
    <td>
      <code>
        items
      </code>
    </td>
    
    <td>
      <code>
        MagicBentoItem[]
      </code>
    </td>
    
    <td>
      Six feature cards
    </td>
    
    <td>
      Cards to show
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        columns
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        4
      </code>
    </td>
    
    <td>
      Columns on wide screens. Drops to 2, then 1, as the grid gets narrower
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        row-height
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        200
      </code>
    </td>
    
    <td>
      Height of one row, in px
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        gap
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        12
      </code>
    </td>
    
    <td>
      Space between cards, in px
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        radius
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        20
      </code>
    </td>
    
    <td>
      Corner radius of the cards, in px
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        theme
      </code>
    </td>
    
    <td>
      <code>
        'dark' | 'light'
      </code>
    </td>
    
    <td>
      <code>
        'dark'
      </code>
    </td>
    
    <td>
      Color theme of the cards
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        glow-color
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      Text color
    </td>
    
    <td>
      Color of the lights and the accents in the artwork. Hex or <code>
        r, g, b
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        enable-border-glow
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      Lights up the card edges near the cursor, across neighboring cards too
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        enable-spotlight
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      A soft light follows the cursor inside the hovered card
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        spotlight-radius
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        300
      </code>
    </td>
    
    <td>
      Size of the cursor light, in px
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        enable-stars
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        false
      </code>
    </td>
    
    <td>
      Fine specks of light drift up around the cursor in the hovered card
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        particle-count
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        24
      </code>
    </td>
    
    <td>
      Number of specks in each card
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        enable-tilt
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        false
      </code>
    </td>
    
    <td>
      Tilts the hovered card toward the cursor
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        enable-magnetism
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        false
      </code>
    </td>
    
    <td>
      The hovered card leans a few pixels toward the cursor
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        click-effect
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      Clicking sends a ring of light across the grid and replays the card artwork
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        text-auto-hide
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      Keeps titles to one line and descriptions to two
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        intro
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      Cards rise in one by one and their artwork plays when the grid scrolls into view
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        disable-animations
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        false
      </code>
    </td>
    
    <td>
      Turns off all motion. Reduced motion settings do the same
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        class
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        ''
      </code>
    </td>
    
    <td>
      Extra classes for the grid
    </td>
  </tr>
</tbody>
</table>

## Item fields

<table>
<thead>
  <tr>
    <th>
      Field
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        id
      </code>
    </td>
    
    <td>
      <code>
        string | number
      </code>
    </td>
    
    <td>
      Stable key
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        label
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      Small caption next to the icon
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        icon
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      Iconify name, e.g. <code>
        lucide:chart-line
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        title
      </code>
      
      , <code>
        description
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      Card text
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        image
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      Photo that fills the card, with a soft shade under the text
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        visual
      </code>
    </td>
    
    <td>
      <code>
        MagicBentoVisual | string
      </code>
    </td>
    
    <td>
      A built-in artwork name, or the name of a slot you pass (scoped <code>
        { item, index }
      </code>
      
      )
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        content
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      Name of a slot that replaces the whole inside of the card. Lights and wave still apply
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        href
      </code>
      
      , <code>
        target
      </code>
      
      , <code>
        rel
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      Renders the card as a link
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        onClick
      </code>
    </td>
    
    <td>
      <code>
        (event: MouseEvent) => void
      </code>
    </td>
    
    <td>
      Click handler for this card
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        colSpan
      </code>
      
      , <code>
        rowSpan
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      Cells the card covers
    </td>
  </tr>
</tbody>
</table>

## Events

<table>
<thead>
  <tr>
    <th>
      Event
    </th>
    
    <th>
      Payload
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        item-click
      </code>
    </td>
    
    <td>
      <code>
        (item: MagicBentoItem, index: number)
      </code>
    </td>
    
    <td>
      Fired when a card is clicked. Listening makes cards focusable buttons
    </td>
  </tr>
</tbody>
</table>

## Accessibility

- Cards with `href` render as links; cards with `onClick` or an `item-click` listener become `role="button"` with `tabindex="0"` and respond to Enter and Space. Keyboard activation starts the wave from the card center.
- Focused cards show a visible ring.
- The artwork is decorative and marked `aria-hidden`.
- `prefers-reduced-motion: reduce` turns off the intro, artwork animation, tilt, magnetism, stars and the click wave, as `disable-animations` does.
- Ported from [React Bits](https://reactbits.dev/components/magic-bento) by David Haz.
