Marketing Showcase Blocks

Integration Connect Grid

A React component where integration cards drop into a grid in sequence, then flip one by one to a connected state with a drawn checkmark. Autoplay it as a showcase, or let users click to connect and await async authorization.

An integration grid for marketing pages and settings screens alike. When the grid scrolls into view, the cards drop in one after another with a slight tilt and a small landing bounce. From there it can autoplay — every so often the next card moves to "connecting" and then "connected", its border fades to the accent color and a checkmark draws itself in — or hand control to the user: clicking Connect calls the onConnect you provide, shows a spinner while a returned Promise is pending, and reverts with a shake if it fails. Once everything is connected, a summary row ("已連接 N 項服務" — "N services connected") appears at the bottom with a rolling number. The connected list supports controlled and uncontrolled modes.

Bring this into your project

Run this command in your project folder. The CLI adds the source and dependencies; then follow the usage example below.

npx webberui@latest add integration-connect-grid.en

New project or installation trouble? Start here →

Playground

Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.

650
3
Active edited usageDefault props
<IntegrationConnectGrid/>

The complete example includes the preview layout and data. Install the component first, then paste this file into your project.

Installation

npx webberui@latest add https://webberui.com/r/integration-connect-grid.en.json

Or, once registries are configured in components.json, install it as @webberui/integration-connect-grid.

Usage

import { Calendar, HardDrive, Mail } from "lucide-react";
import { IntegrationConnectGrid } from "@/components/ui/integration-connect-grid";

const items = [
  { id: "drive", name: "Cloud Drive", description: "Sync shared folders and attachments", icon: <HardDrive /> },
  { id: "calendar", name: "Calendar Sync", description: "Meetings land on the team calendar", icon: <Calendar /> },
  { id: "mail", name: "Email", description: "Turn inbox threads into tasks", icon: <Mail /> },
];

// Marketing page: autoplay
<IntegrationConnectGrid items={items} autoConnect />

// Settings page: users click to connect
<IntegrationConnectGrid
  items={items}
  onConnect={async (id) => {
    // Run your authorization flow; throwing reverts the card with a shake
    await connectIntegration(id);
  }}
  onConnectedChange={(ids) => console.log(ids)}
/>

Props

PropTypeDefaultDescription
itemsIntegrationConnectItem[]—Integration services to display
connectedstring[]—Controlled list of connected ids; when omitted the component manages it internally (uncontrolled)
defaultConnectedstring[][]Initial connected ids in uncontrolled mode
onConnectedChange(connected: string[]) => void—Called when the connected list changes, with the full new id list
onConnect(id: string) => Promise<void> | void—Called when the user clicks Connect; if it returns a Promise a spinner shows while pending, and a rejection reverts to disconnected with a shake
autoConnectbooleanfalseAfter the entrance finishes, connect each card in order automatically
intervalnumber650Delay between cards in auto-connect mode (ms)
columnsnumber3Column count on wide screens; phones always use at most 2 columns
showSummarybooleantrueShow a summary row at the bottom once everything is connected
accentstring—Accent color for the connected state; defaults to --wb-integration-connect-accent (#10b981)
classNamestring—Passed through to the outermost container

IntegrationConnectItem

FieldTypeDefaultDescription
idstring—Unique id; appears in the connected array and the onConnect argument
namestring—Service name
descriptionstring—One-line description, truncated with an ellipsis when too long
iconReactNode—Icon shown at the top-left of the card; falls back to a generic plug icon

How it works

  • The entrance is triggered by an IntersectionObserver (plays once): each card drops from y: -40, rotate: -4° and opacity 0 on a spring (stiffness 420, damping 24, mass 0.8) with a small landing bounce, staggered by --wb-integration-connect-stagger (default 90ms).
  • Auto-connect starts only after the last card has landed. Every interval it moves the next unconnected card to "connecting", holds for 400ms, then switches it to "connected".
  • On connect, the border fades to --wb-integration-connect-accent over --wb-integration-connect-duration (default 300ms), the checkmark draws in over the same duration, and the card scales to 1.02 and back.
  • When onConnect returns a Promise, the button is disabled and shows a spinner while pending; a rejection or thrown error reverts the card with a horizontal shake, ready to click again. Without onConnect, or when it returns synchronously, the card connects immediately.
  • Columns use CSS grid: columns on wide screens, at most 2 below the sm breakpoint. The summary row reserves a fixed height so it does not push the layout below when it appears.

Accessibility

  • The grid is role="list" and each card is role="listitem", labelled by the service name through aria-labelledby
  • The Connect button is a native button; it sets aria-busy and is disabled while authorization is pending, and is described by the service name via aria-describedby
  • State changes are announced in an aria-live="polite" region, e.g. "Calendar Sync connected" or "Invoicing failed to connect, please try again"
  • The connected state does not rely on color alone: a checkmark and the "Connected" label are shown too. After connecting from the button, focus moves to that card instead of falling back to the top of the page
  • When the user has reduce motion enabled, cards appear immediately, states switch instantly, the checkmark is not drawn, and there is no shake or scale