Interactive Bento
Click a cell to expand it 2×2 within the grid — native CSS Grid, 500 ms back-ease transition, only one cell active at a time.
You'll get access to the interactive demo with a free account.
This effect is part of Effect.Labs — 811 vanilla effects, some free, some premium. Cards has 41 effects, including 6 free. Explore the category →
3 usage examples



How it works
Expansion relies on a single CSS rule: when the expanded class is added to a cell, grid-area: span 2/span 2 !important makes it occupy two columns and two rows. CSS Grid reflows the remaining cells automatically — no JS position calculation, no absolute positioning.
The .5s cubic-bezier(.175, .885, .32, 1.275) transition produces a slight back-ease-out bounce at the end: the cell briefly overshoots its target size before settling. The colored drop shadow and indigo-violet gradient (linear-gradient(135deg, #6366f1 0, #8b5cf6 100%)) animate in the same pass.
The expandCell(e) function handles the toggle: if the clicked cell already carries expanded, it removes it (collapse); otherwise it sweeps all cells in the same parent via e.parentElement.querySelectorAll('.bento-cell') to remove expanded everywhere, then adds it to the clicked cell. Only one cell expanded at a time, with no global state — multiple grids coexist on the same page without conflict.
Accessibility
- prefers-reduced-motion absent: the effect does not detect this system preference — 500 ms transitions play even if the OS requests reduced motion. Add
@media (prefers-reduced-motion: reduce) { .bento-interactive .bento-cell { transition: none } }if your use case requires it. - Cells use
onclickon<div>elements, not<button>— not keyboard-accessible without tabindex or a keydown handler. Replace the divs with<button type="button">for native behavior (tab + Enter/Space). - No
aria-expandedattribute orroleis declared on the cells — a screen reader does not announce the expanded/collapsed state. - Secondary text contrast (#a1a1aa at 70% opacity) on background #1a1a24 falls below the WCAG AA 4.5:1 threshold for small text; the expanded cell (white on indigo) passes the AA test.
- The SVG icon inside each cell lacks
aria-hidden="true"— screen readers may announce it as empty text. Add the attribute to hide it.
Browser compatibility
Requires CSS Grid with `grid-area: span N/span N` and CSS transitions — supported in all modern browsers since 2018.
Without JS, cells display normally in the grid with no expand behaviour — the page remains readable. Without CSS Grid (IE 11), the grid is not rendered; use a flexbox or table layout as a fallback.
The code
HTML structure to paste into your page (CSS + JS available with a premium account):
<div class="bento-container">
<div class="bento-grid bento-interactive" id="interactiveBento">
<div class="bento-cell" onclick="expandCell(this)">
<div class="cell-content">
<div class="expand-icon">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" aria-hidden="true">
<path d="M15 3h6v6M9 21H3v-6M21 3l-7 7M3 21l7-7"></path>
</svg>
</div>
<span>Label</span>
</div>
</div>
<!-- × 6 cells total (4-column × 3-row grid) -->
</div>
</div>
Full HTML + CSS + JS, copy-paste ready — with hundreds of premium effects.
Customize
Options passed to the API or data-* attributes:
| Option / property | Default | Effect |
|---|---|---|
| --bg-elevated | #1a1a24 | Background color of interactive cells at rest. Replace with your surface color. |
| --bg-card | #12121a | Background color of the overall container. Align with your page background. |
| --border | rgba(255,255,255,0.08) | Cell border. Raise the opacity (0.15–0.25) for a more visible grid on a light background. |
| --radius-lg | 0.75rem | Corner radius of each cell. 0 for square tiles, 1rem for a rounded card look. |
| gradient .bento-cell.expanded | linear-gradient(135deg, #6366f1 0, #8b5cf6 100%) | Gradient of the expanded cell. Replace the two hex values with your brand colors, or use a flat background instead. |
| gap .bento-grid | 12px | Spacing between cells. 8 px for density, 16 px for an airy premium card feel. |
| grid-template-columns .bento-interactive | repeat(4, 1fr) | Number of columns. Switch to repeat(3, 1fr) for larger cells or richer per-tile content. |
| transition .bento-interactive .bento-cell | .5s cubic-bezier(.175, .885, .32, 1.275) | Expansion duration and curve. Reduce to .25s ease-out for a tighter management UI, increase to .8s for a cinematic fluid feel. |
FAQ
expandCell scopes its selection to e.parentElement.querySelectorAll('.bento-cell') — each grid manages its own cells with no global state. Two div.bento-grid.bento-interactive side by side work without conflict.<div class="bento-cell" onclick="expandCell(this)"> with a <button type="button" class="bento-cell" onclick="expandCell(this)">: buttons are natively focusable and activatable with Enter/Space. Add aria-expanded dynamically inside expandCell to inform screen readers.display:none or opacity:0; height:0) and reveal it via CSS: .bento-cell.expanded .extra { display:block } — no JS changes needed. The content appears automatically on expansion and hides on collapse.