Dashral Pro is on the wayGet 30% off at launch

Dashral

Integrations hubPro

Your app in the middle of eight tools on an orbit, data moving both ways: syncs come in as dots, pushes go out as squares, and the count climbs; one tool connects as you watch, its link drawing in. Tooltips, a lit link on hover, pause, and icons only on phones.

When to use

  • Your app in the middle of the tools it connects to, data moving both ways.
  • Integration pages, and a live view of syncs in an integrations settings page.

When not to use

  • Products with one or two integrations: a short list with their logos is clearer.
  • Managing integrations (connecting, keys, scopes): a settings list does that work; the hub only shows it.

Usage

Integrations hub with your own data: every prop has the sample as its default, so pass only what you have.

example.tsx
import { useEffect, useRef } from "react"
import { IntegrationsHub, type HubHandle } from "@/components/dashral/blocks/integrations-hub"

const hub = useRef<HubHandle>(null)
useEffect(() => syncs.on("sync", (s) => hub.current?.sync(s.integration, s.direction)), [])

<IntegrationsHub ref={hub} mode="live" integrations={integrations} />

API reference

IntegrationsHub

The section: a heading, the hub in a dotted panel with a Live badge, a quiet message as an integration connects, and Pause, then a row of figures. Every part comes from props, with a sample hub by default.

PropTypeDefault
eyebrowReact.ReactNode"Integrations"
titleReact.ReactNodesample
descriptionReact.ReactNodesample
integrationsIntegration[]

The integrations round your app; a pending one connects partway through the demo (live: on connect()).

sample
syncsnumber

Syncs counted before the first one on screen.

1284
connectedMessage(integration: Integration) => string

What the bar says as an integration connects.

sample
stats{ value: string; label: string }[]

The figures under the diagram; none hides the row.

sample
modeHubProps["mode"]

With your own syncs and connections instead of sample ones (see Hub's mode="live").

—
refReact.Ref<HubHandle>—

Hub

Your product in the middle of its integrations, with data moving both ways: syncs come in as hollow dots, pushes go out as solid squares, and the count climbs. A pending integration connects partway through each loop, its link drawing in from the hub. One requestAnimationFrame loop writes the SVG directly; React doesn't render per frame. Sample syncs by default; with mode="live", only the ones you send (see HubHandle). It stops off screen, in a hidden tab, when paused and (live) with nothing moving; with reduced motion everything is connected and still (live, as you've connected it).

PropTypeDefault
integrationsIntegration[]

Required.

—
syncsnumber

Syncs counted before the first one on screen; live, every sync that lands adds one.

1284
speednumber

How fast it runs: 1 is the usual pace, 2 twice as fast, 0 holds it still.

1
pausedboolean

Brings it to rest where it is (easing down, not stopping in one frame).

false
onConnect(integration: Integration, connected: boolean) => void

Called when the pending integration connects, and again (with false) when the loop starts over (live: when you disconnect it).

—
mode"demo" | "live"

"demo" plays sample syncs on its own; "live" moves one only when you send it (see HubHandle).

"demo"
refReact.Ref<HubHandle>—
classNamestring—

type Integration

PropTypeDefault
idstring—
labelstring—
detailstring

More about it, in a tooltip on hover and keyboard focus (touch screens don't show it, so nothing essential).

—
markReact.ReactNode

Its mark (white, on color).

—
colorstring—
pendingboolean

Not connected yet: in the demo it connects partway through each loop; live, when you call connect().

—

type HubHandle

Moves syncs and connects integrations in a live hub (mode="live").

PropTypeDefault
sync(id: string, direction?: "in" | "out") => void

Sends one sync along an integration's link: "in" from it to your app (a hollow dot), "out" from your app to it (a solid square). A pending integration's syncs are ignored until it's connected. Each one adds to the count as it lands; off screen, in a hidden tab or with reduced motion it isn't drawn, but it's counted at once.

—
connect(id: string) => void

Connects an integration: its link draws in from the hub and it turns live (onConnect hears it).

—
disconnect(id: string) => void

Lets an integration go: its link turns dashed and quiet again.

—