Mantine Border Animate

Logo

@gfazioli/mantine-border-animate

Mantine component offering four border animation variants (beam, glow, gradient, pulse) with customizable colors and full animation control, perfect for creating dynamic, visually engaging UI elements.

Upgrading from 0.x to 1.0

Version 1.0 is a major rewrite of the beam variant. The beam now supports two rendering modes (path and conic) and several props have been removed, renamed, or changed semantics.

Breaking Changes

Removed props

PropReplacement
opacity

Renamed to borderOpacity to avoid ambiguity with the CSS opacity prop from BoxProps

anchor

Removed — no longer needed with the new beam implementation

count

Removed — use colorStops with multiple wedges for similar effects

Removed variant

VariantReplacement
gradient

Use variant="beam" with beamMode="conic" and full colorStops (no transparent gaps) to achieve the same rotating gradient effect

Changed props

Propv0.xv1.0

size (beam)

Pixel size of the traveling circle (64px–480px)

Depends on beamMode: for path mode it's still pixel-based, for conic mode it's angular spread (xs=18°..xl=180°)

New props

PropDescription
beamMode

'path' (default) or 'conic' — choose the beam rendering technique

colorStops

Array of { color, position } for multi-color gradients (beam variant)

borderOpacity

Opacity of the border effect (0–1), replaces opacity

timingFunctionCSS animation timing function override
pauseOnHoverPause animation on hover

Migration examples

Rename opacity to borderOpacity:

// Before
<BorderAnimate opacity={0.5} />

// After
<BorderAnimate borderOpacity={0.5} />

Replace variant="gradient" with conic beam + colorStops:

// Before
<BorderAnimate variant="gradient" colorFrom="red" colorTo="blue" />

// After
<BorderAnimate
  beamMode="conic"
  colorStops={[
    { color: 'red', position: 0 },
    { color: 'blue', position: 50 },
    { color: 'red', position: 100 },
  ]}
/>

Remove anchor and count props:

// Before
<BorderAnimate anchor={50} count={3} />

// After
<BorderAnimate />

Installation

yarn add @gfazioli/mantine-border-animate

After installation import package styles at the root of your application:

import '@gfazioli/mantine-border-animate/styles.css';

You can import styles within a layer @layer mantine-border-animate by importing @gfazioli/mantine-border-animate/styles.layer.css file.

import '@gfazioli/mantine-border-animate/styles.layer.css';

Usage

The BorderAnimate component wraps any element to add stunning animated border effects. It's perfect for creating eye-catching UI elements like cards, buttons, input fields, alerts, and more.

Key Features

  • Multiple animation variants - Choose from beam, glow, or pulse effects
  • Two beam modes - path (uniform size along the border) or conic (rotating gradient wedge)
  • Fully customizable - Control colors, duration, size, blur, and more
  • Works with any element - Wrap buttons, cards, inputs, or any Mantine component
  • Performance optimized - Uses CSS animations for smooth 60fps effects
  • Controllable - Toggle animation on/off, show/hide the border, set static angles
  • Custom color stops - Multi-color gradients with colorStops for both beam modes
  • Pause on hover - Pause animations when hovering with pauseOnHover
  • Accessible - Respects prefers-reduced-motion automatically

Simply wrap your content with BorderAnimate and customize it using props:

Animate Border

This is an example of BorderAnimate component

Size
Radius
Border width
Blur
W
H
Duration
Angle
Border opacity
Color from
Color to
import { BorderAnimate } from '@gfazioli/mantine-border-animate';
import { Flex, Text, Title } from '@mantine/core';

function Demo() {
  return (
    <BorderAnimate >
      <Flex flex={1} direction="column" align="center" justify="center" h="100%" style={{ borderRadius: 'inherit', backgroundColor: 'var(--mantine-color-default)',}}>
        <Title>Animate Border</Title>
        <Text>This is an example of BorderAnimate component</Text>
      </Flex>
    </BorderAnimate>
  );
}

Controlled

You can control the border animation using the show prop.

This is a title

This is a paragraph inside the BorderAnimate component.

import { BorderAnimate } from '@gfazioli/mantine-border-animate';
import { Button, Flex, Paper, Stack, Title } from '@mantine/core';
import { useDisclosure } from '@mantine/hooks';

function Demo() {
  const [show, { toggle }] = useDisclosure(true);

  return (
    <Flex>
      <BorderAnimate show={show} size="lg">
        <Paper withBorder shadow="md" radius="md" p="md">
          <Stack>
            <Title>This is a title</Title>
            <p>This is a paragraph inside the BorderAnimate component.</p>
            <Button onClick={toggle}>Toggle BorderAnimate</Button>
          </Stack>
        </Paper>
      </BorderAnimate>
    </Flex>
  );
}

Animated

You can also control the border animation using the animate prop. If animate is set to true, the border will animate continuously. If animate is set to false, the border will be static. You can control the angle of the border animation using the angle prop.

This is a title

This is a paragraph inside the BorderAnimate component.

import { useState } from 'react';
import { BorderAnimate } from '@gfazioli/mantine-border-animate';
import { AngleSlider, Button, Flex, Paper, Stack, Title } from '@mantine/core';
import { useDisclosure } from '@mantine/hooks';

function Demo() {
  const [animate, { toggle }] = useDisclosure(true);
  const [value, setValue] = useState(0);

  return (
    <Flex>
      <BorderAnimate animate={animate} angle={value} size="lg">
        <Paper withBorder shadow="md" radius="md" p="md">
          <Stack>
            <Title>This is a title</Title>
            <p>This is a paragraph inside the BorderAnimate component.</p>
            <Button onClick={toggle}>Toggle Animation</Button>
          </Stack>
        </Paper>
      </BorderAnimate>
      <AngleSlider
        aria-label="Angle slider"
        value={value}
        onChange={setValue}
        formatLabel={(value) => `${value}°`}
      />
    </Flex>
  );
}

Variant

The BorderAnimate component supports three animation variants, each creating a unique visual effect. Use the variant prop to switch between them.

This is a title

This is a paragraph inside the BorderAnimate component.

import { BorderAnimate } from '@gfazioli/mantine-border-animate';
import { Flex, Paper, Stack, Title } from '@mantine/core';

function Demo() {
  return (
    <Flex justify="center" align="center" direction="column" h={400}>
      <BorderAnimate  size="lg">
        <Paper withBorder shadow="md" radius="md" p="md">
          <Stack>
            <Title>This is a title</Title>
            <p>This is a paragraph inside the BorderAnimate component.</p>
          </Stack>
        </Paper>
      </BorderAnimate>
    </Flex>
  );
}

Beam

The beam variant (default) creates an animated glow that moves around the border. It supports two rendering modes via the beamMode prop:

  • path (default) — a radial-gradient circle that travels along the border perimeter via CSS offset-path. The beam has uniform size at all positions and constant speed along the perimeter.
  • conic — a rotating conic-gradient wedge. The rotation is smooth and continuous, but the beam width varies slightly on rectangular containers (wider at corners, narrower at edges) due to the conic geometry.

Key props for beam variant:

  • beamMode - Rendering mode: 'path' (default) or 'conic'
  • size - For path: pixel size of the traveling circle (xs..xl). For conic: angular spread of the wedge (xs=18°..xl=180° or number 0-50)
  • duration - Controls how fast the beam moves/rotates
  • colorFrom / colorTo - Colors of the beam
  • colorStops - Full control over the gradient (overrides colorFrom/colorTo). For path mode creates a radial-gradient with concentric color rings, for conic mode creates a custom conic-gradient

Glow

The glow variant produces a pulsating glow effect that fades in and out. The entire border area illuminates with a soft, diffused light that pulses rhythmically. This is perfect for attention-grabbing elements or notification indicators.

Key props for glow variant:

  • duration - Controls the pulse speed
  • blur - Adjusts the softness of the glow
  • borderOpacity - Controls the maximum opacity of the glow

Pulse

The pulse variant creates a subtle scaling animation combined with opacity changes. The border gently expands and fades, creating a breathing effect. This variant is excellent for subtle emphasis without being too distracting.

Key props for pulse variant:

  • duration - Controls the pulse rhythm
  • blur - Softens the border effect

Color Stops

The colorStops prop gives you full control over the beam gradient. Each stop has a color (any Mantine color) and a position (0-100%). When provided, it overrides colorFrom/colorTo.

For path mode, colorStops creates a radial-gradient with concentric color rings in the traveling circle. For conic mode, it creates a custom conic-gradient — use transparent stops for beam/wedge effects, or fill the entire circle for a rotating gradient border.

Conic beam

Conic with colorStops

Rainbow

Conic full gradient

Path beam

Path with colorStops

import { BorderAnimate } from '@gfazioli/mantine-border-animate';
import { Box, Flex, Text, Stack } from '@mantine/core';

function Content({ children }: { children: React.ReactNode }) {
  return (
    <Box
      w="100%"
      h="100%"
      p="md"
      style={{
        backgroundColor: 'var(--mantine-color-default)',
        borderRadius: 'var(--mantine-radius-md)',
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
      }}
    >
      {children}
    </Box>
  );
}

function Demo() {
  return (
    <Flex gap="xl" align="center" wrap="wrap">
      {/* Conic beam with custom wedge */}
      <Stack align="center" gap="xs">
        <BorderAnimate
          w={200}
          h={200}
          variant="beam"
          beamMode="conic"
          size="sm"
          duration={5}
          colorStops={[
            { color: 'transparent', position: 0 },
            { color: 'green', position: 20 },
            { color: 'cyan', position: 40 },
            { color: 'yellow', position: 60 },
            { color: 'red', position: 80 },
            { color: 'transparent', position: 100 },
          ]}
        >
          <Content>
            <Text size="sm">Conic beam</Text>
          </Content>
        </BorderAnimate>
        <Text size="xs" c="dimmed">Conic with colorStops</Text>
      </Stack>

      {/* Conic beam as full rotating gradient */}
      <Stack align="center" gap="xs">
        <BorderAnimate
          w={200}
          h={200}
          variant="beam"
          beamMode="conic"
          duration={4}
          colorStops={[
            { color: 'red', position: 0 },
            { color: 'orange', position: 17 },
            { color: 'yellow', position: 33 },
            { color: 'green', position: 50 },
            { color: 'cyan', position: 67 },
            { color: 'blue', position: 83 },
            { color: 'red', position: 100 },
          ]}
        >
          <Content>
            <Text size="sm">Rainbow</Text>
          </Content>
        </BorderAnimate>
        <Text size="xs" c="dimmed">Conic full gradient</Text>
      </Stack>

      {/* Path beam with colorStops */}
      <Stack align="center" gap="xs">
        <BorderAnimate
          w={200}
          h={200}
          variant="beam"
          beamMode="path"
          size="md"
          duration={5}
          colorStops={[
            { color: 'red', position: 0 },
            { color: 'yellow', position: 25 },
            { color: 'cyan', position: 50 },
            { color: 'transparent', position: 70 },
          ]}
        >
          <Content>
            <Text size="sm">Path beam</Text>
          </Content>
        </BorderAnimate>
        <Text size="xs" c="dimmed">Path with colorStops</Text>
      </Stack>
    </Flex>
  );
}

Animation Control

Pause on Hover

Set pauseOnHover to pause the animation when the user hovers over the component. This is useful for interactive elements where the animation might be distracting during interaction.

Hover me!

Beam pauses on hover

Hover me!

Gradient pauses on hover

import { BorderAnimate } from '@gfazioli/mantine-border-animate';
import { Box, Flex, Text, Stack } from '@mantine/core';

function Content({ children }: { children: React.ReactNode }) {
  return (
    <Box
      w="100%"
      h="100%"
      p="md"
      style={{
        backgroundColor: 'var(--mantine-color-default)',
        borderRadius: 'var(--mantine-radius-md)',
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
      }}
    >
      {children}
    </Box>
  );
}

function Demo() {
  return (
    <Flex gap="xl" align="center">
      <Stack align="center" gap="xs">
        <BorderAnimate w={200} h={150} pauseOnHover>
          <Content>
            <Text size="sm">Hover me!</Text>
          </Content>
        </BorderAnimate>
        <Text size="xs" c="dimmed">Beam pauses on hover</Text>
      </Stack>

      <Stack align="center" gap="xs">
        <BorderAnimate w={200} h={150} variant="glow" blur="sm" pauseOnHover duration={3}>
          <Content>
            <Text size="sm">Hover me!</Text>
          </Content>
        </BorderAnimate>
        <Text size="xs" c="dimmed">Gradient pauses on hover</Text>
      </Stack>
    </Flex>
  );
}

Timing Function

The timingFunction prop controls the CSS animation timing function. By default, beam uses linear (constant speed), while glow and pulse use ease-in-out (smooth acceleration). You can override this with any valid CSS timing function.

linear

Constant speed

ease-in-out

Smooth acceleration

steps(8)

Stepped / retro

import { BorderAnimate } from '@gfazioli/mantine-border-animate';
import { Box, Flex, Text, Stack } from '@mantine/core';

function Content({ children }: { children: React.ReactNode }) {
  return (
    <Box
      w="100%"
      h="100%"
      p="md"
      style={{
        backgroundColor: 'var(--mantine-color-default)',
        borderRadius: 'var(--mantine-radius-md)',
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
      }}
    >
      {children}
    </Box>
  );
}

function Demo() {
  return (
    <Flex gap="xl" align="center">
      <Stack align="center" gap="xs">
        <BorderAnimate w={180} h={120} timingFunction="linear">
          <Content>
            <Text size="xs">linear</Text>
          </Content>
        </BorderAnimate>
        <Text size="xs" c="dimmed">Constant speed</Text>
      </Stack>

      <Stack align="center" gap="xs">
        <BorderAnimate w={180} h={120} timingFunction="ease-in-out">
          <Content>
            <Text size="xs">ease-in-out</Text>
          </Content>
        </BorderAnimate>
        <Text size="xs" c="dimmed">Smooth acceleration</Text>
      </Stack>

      <Stack align="center" gap="xs">
        <BorderAnimate w={180} h={120} timingFunction="steps(8)">
          <Content>
            <Text size="xs">steps(8)</Text>
          </Content>
        </BorderAnimate>
        <Text size="xs" c="dimmed">Stepped / retro</Text>
      </Stack>
    </Flex>
  );
}

Mask and Background Effects

The withMask and zIndex props allow you to create advanced visual effects, including background glows and layered animations.

withMask

By default, withMask is true, which clips the animated effect to the border area only. Set withMask={false} to let the glow extend beyond the border, creating a softer, more diffused effect. Both beam modes (path and conic) support masking.

Path + mask

Clipped to border

Path no mask

Glow extends outward

Conic + mask

Conic clipped

Conic no mask

Conic full gradient

import { BorderAnimate } from '@gfazioli/mantine-border-animate';
import { Box, Flex, Text, Stack } from '@mantine/core';

function Content({ children }: { children: React.ReactNode }) {
  return (
    <Box
      w="100%"
      h="100%"
      p="md"
      style={{
        backgroundColor: 'var(--mantine-color-default)',
        borderRadius: 'var(--mantine-radius-md)',
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
      }}
    >
      {children}
    </Box>
  );
}

function Demo() {
  return (
    <Flex gap="xl" align="center" wrap="wrap">
      {/* Path mode: withMask={true} */}
      <Stack align="center" gap="xs">
        <BorderAnimate w={200} h={150} withMask size="lg" blur={4}>
          <Content>
            <Text size="xs">Path + mask</Text>
          </Content>
        </BorderAnimate>
        <Text size="xs" c="dimmed">Clipped to border</Text>
      </Stack>

      {/* Path mode: withMask={false} */}
      <Stack align="center" gap="xs">
        <BorderAnimate w={200} h={150} withMask={false} size="lg" blur={4}>
          <Content>
            <Text size="xs">Path no mask</Text>
          </Content>
        </BorderAnimate>
        <Text size="xs" c="dimmed">Glow extends outward</Text>
      </Stack>

      {/* Conic mode: withMask={true} */}
      <Stack align="center" gap="xs">
        <BorderAnimate w={200} h={150} beamMode="conic" withMask size="md" blur="xs">
          <Content>
            <Text size="xs">Conic + mask</Text>
          </Content>
        </BorderAnimate>
        <Text size="xs" c="dimmed">Conic clipped</Text>
      </Stack>

      {/* Conic mode: withMask={false} */}
      <Stack align="center" gap="xs">
        <BorderAnimate w={200} h={150} beamMode="conic" withMask={false} size="md" blur="xs">
          <Content>
            <Text size="xs">Conic no mask</Text>
          </Content>
        </BorderAnimate>
        <Text size="xs" c="dimmed">Conic full gradient</Text>
      </Stack>
    </Flex>
  );
}

zIndex

The zIndex prop controls the stacking order of the border effect. By default, the border appears in front of the content (zIndex={1}). Set zIndex={-1} combined with withMask={false} to create beautiful background glow effects that appear behind your content.

zIndex=1

Border in front

zIndex=-1

Background glow

Layered

Front + background

import { BorderAnimate } from '@gfazioli/mantine-border-animate';
import { Box, Flex, Text, Stack } from '@mantine/core';

function Content({ children }: { children: React.ReactNode }) {
  return (
    <Box
      w="100%"
      h="100%"
      p="md"
      style={{
        backgroundColor: 'var(--mantine-color-default)',
        borderRadius: 'var(--mantine-radius-md)',
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
      }}
    >
      {children}
    </Box>
  );
}

function Demo() {
  return (
    <Flex gap="xl" align="center">
      {/* Default: zIndex={1} - border is in front */}
      <Stack align="center" gap="xs">
        <BorderAnimate w={200} h={150} zIndex={1} size="lg" blur={4}>
          <Content>
            <Text size="sm">zIndex=1</Text>
          </Content>
        </BorderAnimate>
        <Text size="xs" c="dimmed">Border in front</Text>
      </Stack>

      {/* zIndex={-1} with withMask={false} - creates background glow effect */}
      <Stack align="center" gap="xs">
        <BorderAnimate w={200} h={150} zIndex={-1} withMask={false} size="xl" blur={14} borderOpacity={0.5}>
          <Content>
            <Text size="sm">zIndex=-1</Text>
          </Content>
        </BorderAnimate>
        <Text size="xs" c="dimmed">Background glow</Text>
      </Stack>

      {/* Combined: layered effect with multiple borders */}
      <Stack align="center" gap="xs">
        <BorderAnimate w={200} h={150} size="md">
          <BorderAnimate w={200} h={150} zIndex={-1} withMask={false} size="xl" blur={20} borderOpacity={0.3} colorFrom="#ff6b6b" colorTo="#2b00ff" duration={8}>
            <Content>
              <Text size="sm">Layered</Text>
            </Content>
          </BorderAnimate>
        </BorderAnimate>
        <Text size="xs" c="dimmed">Front + background</Text>
      </Stack>
    </Flex>
  );
}

Use Cases

BorderAnimate can be used with virtually any Mantine component. Here are some common use cases to inspire your implementations.

Buttons

Add animated borders to buttons to make them stand out. Perfect for call-to-action buttons, submit buttons, or any interactive element that needs extra attention.

import { BorderAnimate } from '@gfazioli/mantine-border-animate';
import { Button, Flex } from '@mantine/core';

function Demo() {
  return (
    <Flex gap="xl" align="center">
      <BorderAnimate radius={4} size="sm">
        <Button>Click me</Button>
      </BorderAnimate>

      <BorderAnimate radius={256} size="sm">
        <Button radius={256} variant="default">
          Rounded
        </Button>
      </BorderAnimate>

      <BorderAnimate radius="md" size="md" variant="glow" blur="xs">
        <Button variant="light" color="violet">
          Gradient
        </Button>
      </BorderAnimate>
    </Flex>
  );
}

Input Fields

Highlight input fields with animated borders to guide users through forms or indicate active/focused states.

import { BorderAnimate } from '@gfazioli/mantine-border-animate';
import { Input } from '@mantine/core';

function Demo() {
  return (
    <BorderAnimate size="xs" radius="sm">
      <Input placeholder="Your email" />
    </BorderAnimate>
  );
}

Alerts and Notifications

Make alerts more noticeable with animated borders. Use different variants and colors to convey urgency levels.

import { IconInfoCircle, IconAlertTriangle } from '@tabler/icons-react';
import { BorderAnimate } from '@gfazioli/mantine-border-animate';
import { Alert, Flex } from '@mantine/core';

function Demo() {
  return (
    <Flex direction="column" align="center" gap="xl" py={64}>
      <BorderAnimate size="lg" radius="sm" duration={10}>
        <Alert
          variant="light"
          color="blue"
          title="Information"
          icon={<IconInfoCircle />}
        >
          This is an informational alert with an animated border effect.
        </Alert>
      </BorderAnimate>

      <BorderAnimate
        size="lg"
        radius="sm"
        duration={2}
        colorFrom="red"
        colorTo="orange"
        variant="glow"
      >
        <Alert
          variant="light"
          color="red"
          title="Warning"
          icon={<IconAlertTriangle />}
        >
          This is a warning alert with a glowing border effect.
        </Alert>
      </BorderAnimate>
    </Flex>
  );
}

Cards

Create premium-looking cards with animated borders. Great for featured content, pricing cards, or special offers.

Norway

Premium Package

On Sale

Get access to all premium features with our special animated border effect that highlights this exclusive offer.

import { BorderAnimate } from '@gfazioli/mantine-border-animate';
import { Card, Image, Text, Badge, Button, Group } from '@mantine/core';

function Demo() {
  return (
    <BorderAnimate variant="glow" blur="md" radius="md" duration={3}>
      <Card shadow="sm" padding="lg" radius="md" withBorder w={340}>
        <Card.Section>
          <Image
            src="https://raw.githubusercontent.com/mantinedev/mantine/master/.demo/images/bg-8.png"
            height={160}
            alt="Norway"
          />
        </Card.Section>

        <Group justify="space-between" mt="md" mb="xs">
          <Text fw={500}>Premium Package</Text>
          <Badge color="pink">On Sale</Badge>
        </Group>

        <Text size="sm" c="dimmed">
          Get access to all premium features with our special animated
          border effect that highlights this exclusive offer.
        </Text>

        <Button color="blue" fullWidth mt="md" radius="md">
          Get Started
        </Button>
      </Card>
    </BorderAnimate>
  );
}

Chips and Badges

Even small elements like chips can benefit from animated borders to indicate selection or special status.

import { BorderAnimate } from '@gfazioli/mantine-border-animate';
import { Chip, Flex } from '@mantine/core';

function Demo() {
  return (
    <Flex gap="md" align="center">
      <BorderAnimate size="xs" radius="xl">
        <Chip defaultChecked>Selected</Chip>
      </BorderAnimate>

      <BorderAnimate size="xs" radius="xl" variant="pulse" colorTo="white" p={3}>
        <Chip defaultChecked color="green">Active</Chip>
      </BorderAnimate>

      <BorderAnimate size="xs" radius="xl" variant="pulse" duration={2}>
        <Chip defaultChecked color="violet">Premium</Chip>
      </BorderAnimate>
    </Flex>
  );
}

Accordion

Wrap accordion components with animated borders to create visually engaging expandable sections. The border effect adds a modern touch to FAQ sections or collapsible content areas.

Crisp and refreshing fruit. Apples are known for their versatility and nutritional benefits.
import { BorderAnimate } from '@gfazioli/mantine-border-animate';
import { Accordion } from '@mantine/core';

const data = [
  {
    emoji: '🍎',
    value: 'Apples',
    description:
      'Crisp and refreshing fruit. Apples are known for their versatility and nutritional benefits.',
  },
  {
    emoji: '🍌',
    value: 'Bananas',
    description:
      'Naturally sweet and potassium-rich fruit. Bananas are a popular choice for energy-boosting.',
  },
  {
    emoji: '🥦',
    value: 'Broccoli',
    description:
      'Nutrient-packed green vegetable. Broccoli is packed with vitamins, minerals, and fiber.',
  },
];

function Demo() {
  const items = data.map((item) => (
    <Accordion.Item key={item.value} value={item.value}>
      <Accordion.Control icon={item.emoji}>{item.value}</Accordion.Control>
      <Accordion.Panel>{item.description}</Accordion.Panel>
    </Accordion.Item>
  ));

  return (
    <BorderAnimate size="lg" radius="md">
      <Accordion variant="contained" defaultValue="Apples">
        {items}
      </Accordion>
    </BorderAnimate>
  );
}

Multiple Borders

Nest multiple BorderAnimate components to create complex, layered effects. Combine different variants, speeds, directions, and colors to achieve unique visual compositions. This technique is perfect for hero sections or premium UI elements that need extra visual impact.

Multiple Animated Borders

import { BorderAnimate } from '@gfazioli/mantine-border-animate';
import { Box, Flex, Text } from '@mantine/core';

function Content({ children }: { children: React.ReactNode }) {
  return (
    <Box
      w="100%"
      h="100%"
      p="md"
      style={{
        backgroundColor: 'var(--mantine-color-default)',
        borderRadius: 'var(--mantine-radius-md)',
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
      }}
    >
      {children}
    </Box>
  );
}

function Demo() {
  return (
    <BorderAnimate w={400} h={250}>
      <BorderAnimate w={400} h={250} duration={55} reverse borderWidth={1} size="xl" colorFrom="#ff6b6b" colorTo="#2b00ff">
        <BorderAnimate w={400} h={250} duration={23} withMask={false} size="xl" borderOpacity={0.2} blur={14} zIndex={-1}>
          <BorderAnimate w={400} h={250} variant="glow" blur={4}>
            <Content>
              <Text fw={500}>Multiple Animated Borders</Text>
            </Content>
          </BorderAnimate>
        </BorderAnimate>
      </BorderAnimate>
    </BorderAnimate>
  );
}

Circular Elements

BorderAnimate works perfectly with circular shapes. Set radius="100%" to create animated borders around avatars, profile pictures, or any circular UI element. The beam smoothly follows the circular path.

Circle

Simple circle

Avatar

Avatar

Gradient

Gradient variant

import { BorderAnimate } from '@gfazioli/mantine-border-animate';
import { Avatar, Box, Flex, Stack, Text } from '@mantine/core';

function CircleContent({ children }: { children: React.ReactNode }) {
  return (
    <Box
      w="100%"
      h="100%"
      style={{
        backgroundColor: 'var(--mantine-color-default)',
        borderRadius: '100%',
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
      }}
    >
      {children}
    </Box>
  );
}

function Demo() {
  return (
    <Flex gap="xl" align="center">
      {/* Simple circle */}
      <Stack align="center" gap="xs">
        <BorderAnimate w={100} h={100} radius="100%">
          <CircleContent>
            <Text size="xs">Circle</Text>
          </CircleContent>
        </BorderAnimate>
        <Text size="xs" c="dimmed">Simple circle</Text>
      </Stack>

      {/* Avatar with glow */}
      <Stack align="center" gap="xs">
        <BorderAnimate w={80} h={80} variant="glow" radius="100%" size="sm" colorFrom="green" colorTo="cyan">
          <Avatar
            src="https://raw.githubusercontent.com/mantinedev/mantine/master/.demo/avatars/avatar-1.png"
            alt="Avatar"
            radius="100%"
            size={80}
          />
        </BorderAnimate>
        <Text size="xs" c="dimmed">Avatar</Text>
      </Stack>

      {/* Larger circle with gradient variant */}
      <Stack align="center" gap="xs">
        <BorderAnimate w={120} h={120} radius="100%" variant="pulse" duration={3}>
          <CircleContent>
            <Text size="xs">Gradient</Text>
          </CircleContent>
        </BorderAnimate>
        <Text size="xs" c="dimmed">Gradient variant</Text>
      </Stack>
    </Flex>
  );
}

Accessibility

BorderAnimate automatically respects the prefers-reduced-motion media query. When a user has enabled "Reduce motion" in their operating system settings, all animations are disabled. No additional configuration is needed.