Integration Beams
The product in the middle, its integrations around it, and data travelling along the lines between them: up to eight on the lines, more on a ring around the product. The drawing is decoration hidden from screen readers; the integrations are also a real list under it, with links where they have one. Zero JavaScript.
Live demo
Sample integrations
One product, ten sample services
Every mark here is drawn for this demo. The list under the drawing is what a screen reader reads.
- Sample Mail
- Sample Pay
- Sample Chat
- Sample Docs
- Sample Store
- Sample CRM
- Sample Calendar
- Sample Analytics
- Sample Maps
- Sample Forms
Live, from the library itself, at full size: scroll, hover, navigate away and back. The demo is never gated.
Variants · each row writes the attribute the prop writes; the section's own CSS answers
Measured
JavaScript of its own
0 B
CSS 16.5 kB raw including the base tokens. Measured from a production build, and again in CI for every change that can move it.
Browser support
Chrome 120 · Firefox 121 · Safari 16; needs container-units, css-exp, has. Elsewhere: without container units or hypot() the lines draw solid and nothing travels; the ring is laid out from count, so it needs no :has().
Install Pro
The demo above is never gated; the source is. With a key in components.json (see account), the registry serves it like any other item:
npx shadcn@latest add @moonarc-pro/integration-beams---
import IntegrationBeams from '@/components/moonarc/pro/IntegrationBeams.astro';
import mark from '../assets/mark.svg';
import mail from '../assets/integrations/mail.svg';
import pay from '../assets/integrations/pay.svg';
import chat from '../assets/integrations/chat.svg';
---
<IntegrationBeams
eyebrow="Integrations"
headline="Works with the tools you already use"
hub={{ src: mark, alt: 'Your product' }}
integrations={[
{ name: 'Mail', logo: mail, href: '/integrations/mail/' },
{ name: 'Payments', logo: pay, href: '/integrations/pay/' },
{ name: 'Chat', logo: chat },
]}
/>Without a key the registry answers 401 with an upgrade message. Everything this section composes is free: animated-beam, orbiting-circles, reveal.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
hub | { src, alt? } | none | The product's mark in the middle: an imported image or a URL. The drawing is hidden from screen readers, so alt is only kept on the image. |
integrations | { name, logo, href? }[] | none | The integrations: the first eight on the lines, the rest on the ring (with orbit), every one in the list by name, linked where href is set. logo is an imported image or a URL, drawn square on a round plate. |
layout | 'hub' | 'fan' | 'hub' | hub: the integrations around the product; fan: in a column flowing into the product at the inline end. A right-to-left page mirrors the fan, and the logos are mirrored back. |
orbit | boolean | false | Put the integrations after the eighth (up to twelve more) on a ring around the product. |
list | 'visible' | 'hidden' | 'visible' | The list under the drawing: shown as name chips, or for screen readers only (.ma-sr). |
listLabel | string | 'Integrations' | Accessible name of the list. |
cycles | number | none | Rounds the packets travel once the drawing is in view (Reveal, the shared script, marks it), setting off in turn, before the lines rest. Unset, they travel while the page is open. One round of eight lines is over in under five seconds, the limit WCAG 2.2.2 sets for motion with no control. |
headline | string | none | The section's h2. The headline slot wins over it. |
eyebrow | string | none | Small label above the headline. The eyebrow slot wins over it. |
copy | string | none | Supporting copy under the headline. The copy slot wins over it. |
tone | 'surface' | 'muted' | 'ink' | 'brand' | unset (paints nothing) | The ground: the page surface, a muted band, an always-dark ink panel, or a deep brand panel. Each paints --background, --ma-tone-muted (over --muted, with a --border hairline), --ma-tone-ink or --ma-tone-brand (over --primary) with the matching text. The packets are the brand colour, and the tone's text on ink and brand. |
density | 'compact' | 'cozy' | 'roomy' | 'cozy' | Block padding and the gaps ×0.8 / ×1 / ×1.25 through --ma-density. |
align | 'center' | 'start' | 'center' | Alignment of the head, the list and the actions; the drawing stays centred. |
Theming and overrides
The section reads the theme contract (shadcn's variable names with the base tokens as fallback), so a pasted theme or one --ma-brand recolours it. Its class names are the override surface and stay stable; a named slot replaces the matching prop with your own markup.
Classes
.ma-in.ma-integration-beams.ma-integration-beams__actions.ma-integration-beams__copy.ma-integration-beams__cue.ma-integration-beams__diagram.ma-integration-beams__eyebrow.ma-integration-beams__head.ma-integration-beams__headline.ma-integration-beams__hub.ma-integration-beams__inner.ma-integration-beams__list.ma-integration-beams__node.ma-integration-beams__ring
Slots
slot="eyebrow"slot="headline"slot="copy"slot="actions"
Reduced motion
The lines are drawn whole at 60 % and the ring stands still.
With ClientRouter
Inherits AnimatedBeam and OrbitingCircles; nothing to wire, both are CSS only.
Why it is built this way
- Nothing in the drawing takes focus: a link to an integration lives in the list, where a screen reader and the keyboard both reach it.
- The packets set off one after another, spread over one trip, so the lines never pulse together.
- The ring's radius is a share of the drawing's width, so it sits between the product and the lines at any size.
Replaces: AnimatedBeam integrations (Magic UI) · Integrations section (shadcnblocks). See the migration table.
Related
Orbiting Circles
BackgroundsThe children orbit the centre of their parent and stay upright.
A grid of integrations, tools or partners: cards with an icon, a name and a line, each lit by a spotlight that follows the cursor and lifting on hover, revealed with a tight stagger..
Also: view transitions · how costs are measured · browser support · accessibility policy · five-minute setup · MCP for agents · this page as Markdown