Skip to content

Components / Sections

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

tone
density
align

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

Baseline · widely available

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:

terminal
npx shadcn@latest add @moonarc-pro/integration-beams
src/pages/index.astro
---
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

PropTypeDefaultDescription
hub{ src, alt? }noneThe 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? }[]noneThe 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.
orbitbooleanfalsePut 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).
listLabelstring'Integrations'Accessible name of the list.
cyclesnumbernoneRounds 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.
headlinestringnoneThe section's h2. The headline slot wins over it.
eyebrowstringnoneSmall label above the headline. The eyebrow slot wins over it.
copystringnoneSupporting 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

Replaces: AnimatedBeam integrations (Magic UI) · Integrations section (shadcnblocks). See the migration table.

Animated Beam

Backgrounds

Sends packets of light along curves between nodes.

every browseralways

Orbiting Circles

Backgrounds

The children orbit the centre of their parent and stay upright.

every browseralways

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..

every browserscrollpointer

Also: view transitions · how costs are measured · browser support · accessibility policy · five-minute setup · MCP for agents · this page as Markdown