Svelte 5 component · fractalsvelte-ui · Motion
FloatingBadge
A status badge elevated with gentle sinusoidal vertical float animation and an optional pulsing live indicator dot. Ideal for feature highlights, live states, and operational health metrics.
Install
FloatingBadge is a Svelte 5 floating badge component in @fractaldesign/fractalsvelte-ui. It works in SvelteKit and in any Svelte 5 app.
pnpm add @fractaldesign/fractalsvelte-uiImport
import { FloatingBadge } from '@fractaldesign/fractalsvelte-ui';Usage
<FloatingBadge variant={'primary'} size={'md'} duration={3}>Click me</FloatingBadge>Props
Also accepts every attribute of HTMLAttributes, spread onto
the root element.
| Name | Type | Default |
|---|---|---|
variant | Variant 'primary' | 'secondary' | 'soft' | 'outline' | 'ghost' | 'destructive' | 'surface' | 'primary' |
size | Size 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'md' |
duration | number | 3 |
amplitude | number | 4 |
dot | boolean | true |
pulse | boolean | true |
class | string | '' |
Snippets
| Name | Type | Default |
|---|---|---|
children | Snippet | — |
leading | Snippet | — |
Source
Show the FloatingBadge.svelte source
<script lang="ts">
import type { Snippet } from 'svelte';
import type { HTMLAttributes } from 'svelte/elements';
import type { Variant, Size } from '../../types';
interface Props extends HTMLAttributes<HTMLSpanElement> {
variant?: Variant;
size?: Size;
duration?: number;
amplitude?: number;
dot?: boolean;
pulse?: boolean;
class?: string;
children?: Snippet;
leading?: Snippet;
}
let {
variant = 'primary',
size = 'md',
duration = 3,
amplitude = 4,
dot = true,
pulse = true,
class: className = '',
children,
leading,
...restProps
}: Props = $props();
</script>
<span
class="f-floating-badge {className}"
data-variant={variant}
data-size={size}
style="--float-duration: {duration}s; --float-amplitude: {amplitude}px;"
{...restProps}
>
{#if dot}
<span class="f-badge-dot" data-pulse={pulse ? 'true' : undefined} aria-hidden="true">
{#if pulse}
<span class="f-badge-dot-ping"></span>
{/if}
<span class="f-badge-dot-core"></span>
</span>
{/if}
{#if leading}
<span class="f-badge-leading">{@render leading()}</span>
{/if}
{#if children}
<span class="f-badge-content">{@render children()}</span>
{/if}
</span>
<style>
@layer fractalsvelte-ui.components {
.f-floating-badge {
position: relative;
display: inline-flex;
align-items: center;
gap: var(--f-space-xs);
font-family: var(--f-font-sans);
font-weight: 500;
line-height: 1;
white-space: nowrap;
border-radius: var(--f-radius-full);
border: 1px solid transparent;
box-sizing: border-box;
animation: f-float-anim var(--float-duration) ease-in-out infinite alternate;
box-shadow: var(--f-shadow-sm);
}
/* Sizes */
.f-floating-badge[data-size='xs'] {
padding: 0.2rem 0.5rem;
font-size: var(--f-text-xs);
}
.f-floating-badge[data-size='sm'] {
padding: 0.25rem 0.625rem;
font-size: var(--f-text-xs);
}
.f-floating-badge[data-size='md'] {
padding: 0.375rem 0.875rem;
font-size: var(--f-text-sm);
}
.f-floating-badge[data-size='lg'] {
padding: 0.5rem 1rem;
font-size: var(--f-text-base);
}
.f-floating-badge[data-size='xl'] {
padding: 0.625rem 1.25rem;
font-size: var(--f-text-lg);
}
/* Variants */
.f-floating-badge[data-variant='primary'] {
background: var(--f-primary-subtle);
color: var(--f-primary);
border-color: rgba(16, 185, 129, 0.3);
}
.f-floating-badge[data-variant='secondary'] {
background: var(--f-panel);
color: var(--f-text);
border-color: var(--f-border);
}
.f-floating-badge[data-variant='soft'] {
background: var(--f-hover);
color: var(--f-text);
border-color: transparent;
}
.f-floating-badge[data-variant='outline'] {
background: transparent;
color: var(--f-text);
border-color: var(--f-border-strong);
}
.f-floating-badge[data-variant='ghost'] {
background: transparent;
color: var(--f-text-muted);
border-color: transparent;
box-shadow: none;
}
.f-floating-badge[data-variant='destructive'] {
background: var(--f-danger-bg);
color: var(--f-danger);
border-color: rgba(239, 68, 68, 0.3);
}
.f-floating-badge[data-variant='surface'] {
background: var(--f-surface);
color: var(--f-text);
border-color: var(--f-border);
}
/* Float Keyframe */
@keyframes f-float-anim {
0% {
transform: translateY(0);
}
100% {
transform: translateY(calc(-1 * var(--float-amplitude)));
}
}
/* Dot */
.f-badge-dot {
position: relative;
display: inline-flex;
align-items: center;
justify-content: center;
width: 0.5rem;
height: 0.5rem;
}
.f-badge-dot-core {
position: relative;
width: 100%;
height: 100%;
border-radius: var(--f-radius-full);
background: currentColor;
}
.f-badge-dot-ping {
position: absolute;
inset: -2px;
border-radius: var(--f-radius-full);
background: currentColor;
opacity: 0.6;
animation: f-ping 1.6s cubic-bezier(0, 0, 0.2, 1) infinite;
}
@keyframes f-ping {
75%, 100% {
transform: scale(2.4);
opacity: 0;
}
}
.f-badge-leading,
.f-badge-content {
display: inline-flex;
align-items: center;
}
}
</style>Related components
GlowCard A card container wrapped in a cursor-tracking radial spotlight border glow.LidarSweep A circular radar sweep or linear LiDAR plane scanner featuring rotating beam gradients, range rings,…MagneticButton A physics-driven button that smoothly pulls toward cursor coordinates within its interaction perimeter and…MagnetLines A dynamic directional matrix of vector line needles that orient toward pointer coordinates using real-time…Marquee An infinite horizontal scrolling ticker that loops arbitrary child content smoothly without jitter.RippleEffect A tactile touch and click container that emits radial waves expanding from the exact pointer down coordinates.