Components/GradientBorder

GradientBorder

Animated gradient border wrapper for highlighting cards, hero panels, and callout containers.

VerifiedSince 0.3.4

Usage

Loading demo...

Semantic Root

Use as when the highlighted surface should be a semantic landmark or list item.

<template>
  <TxGradientBorder as="section" :border-width="3" :border-radius="20" padding="1rem 1.25rem">
    <article class="rounded-[16px] bg-[var(--tx-bg-color)] p-4">
      <h3>Release candidate</h3>
      <p>Ready for manual QA.</p>
    </article>
  </TxGradientBorder>
</template>

Custom Units

Numeric sizing props become pixels. String props are preserved, so CSS variables and multi-value padding are valid.

<template>
  <TxGradientBorder
    border-width="0.125rem"
    border-radius="var(--radius-lg)"
    padding="1rem 1.5rem"
    :animation-duration="6"
  >
    <div class="rounded-[inherit] bg-[var(--tx-bg-color)] p-4">
      Uses project tokens
    </div>
  </TxGradientBorder>
</template>

Best Practices

  • Put a real surface inside the wrapper and align its radius with borderRadius - borderWidth to avoid exposed corners.
  • Use semantic as values for sections, list items, or articles instead of adding extra wrapper landmarks around the component.
  • Keep animationDuration slower on dense pages; multiple fast animated borders compete with primary content.
  • Avoid wrapping controls whose focus rings must escape the border unless the inner content handles focus styling itself.
  • Prefer one highlighted gradient surface per view region; use TxBadge or TxTag for smaller status accents.
  • Under prefers-reduced-motion: reduce the rotation is disabled and the border settles at a static gradient angle.

API Reference

Props

PropTypeDefaultDescription
asstring'div'Root element tag rendered by the wrapper.
borderWidthstring | number'2px'Gradient border width. Numbers become px.
borderRadiusstring | number'12px'Border radius applied to the wrapper and gradient layer. Numbers become px.
paddingstring | number'12px'Padding applied to the inner content wrapper. Numbers become px.
animationDurationnumber4Gradient rotation duration in seconds.

Slots

SlotPropsDescription
default-Content rendered inside .tx-gradient-border__inner.

Events

No public events are emitted.

Exposed Methods

No public instance methods are exposed.

CSS Variables

VariableSourceDescription
--tx-gradient-border-widthborderWidthBorder thickness and blur distance.
--tx-gradient-border-radiusborderRadiusWrapper and gradient radius.
--tx-gradient-inner-paddingpaddingInner wrapper padding.
--tx-gradient-durationanimationDurationRotation animation duration.
--tx-gradient-angleinternal animationRegistered angle property used by the gradient.

Overview

  • The root element is rendered by <component :is="as">; default root is div.
  • The component renders one inner wrapper, .tx-gradient-border__inner, around the default slot.
  • borderWidth, borderRadius, and padding accept numbers or strings. Numbers are normalized to px; strings are passed through unchanged.
  • animationDuration is numeric seconds and is written to --tx-gradient-duration with an s suffix.
  • The gradient ring is drawn in a separate aria-hidden layer, .tx-gradient-border__ring, with pointer-events: none; the slotted content owns all actual interaction.
  • The ring is cut from a filled box, so it follows borderRadius, and its blur is not clipped: the glow spreads past the wrapper's edge on both sides.
  • .tx-gradient-border__inner uses overflow: hidden with the same radius, so child focus rings or shadows can be clipped when they extend outside it.

Technologies

  • Reviewed against packages/tuffex/packages/components/src/gradient-border/index.ts, TxGradientBorder.vue, and gradient-border.test.ts.
  • Props are declared in index.ts; there is no separate src/types.ts for this component.
  • The animated gradient is a non-interactive layer. Slotted content remains responsible for all interaction and focus styling.
  • Ring drawing: the ring used to be a blurred border-image on a ::before inside an overflow: hidden root. border-image ignores border-radius, so the frame was square and the rounded clip cut each corner away, and the same clip cut the outer half of the blur off flat. The blur now sits on its own layer and the ring shape on its child, because filter runs before mask on a single element.
  • Component source: packages/tuffex/packages/components/src/gradient-border/src/TxGradientBorder.vue.
  • Types: packages/tuffex/packages/components/src/gradient-border/index.ts.
  • Verified coverage: Coverage: packages/tuffex/packages/components/src/gradient-border/__tests__/gradient-border.test.ts verifies default root rendering, custom root tags, numeric unit normalization, duration seconds, and string CSS unit preservation.
查看源码
packages/tuffex/packages/components/src/gradient-border/index.ts