Components/Transition
Universal Component

Transition

Preset transition wrapper for content switches, list motion, and smooth size changes.

This page was migrated by AI, please review carefully

Migration is complete, but please validate against source code and manual review.

Transition

TxTransition centralizes the motion presets used by Tuffex components. It wraps Vue Transition / TransitionGroup, maps timing props to CSS variables, and switches to TxTransitionSmoothSize for size-aware content changes.

Content Switch (X)

Transition Content

Demo will load when visible.
<script setup lang="ts">
import { computed, ref } from 'vue'

type Preset = 'fade' | 'slide-fade' | 'rebound' | 'smooth-size'

const preset = ref<Preset>('fade')
const value = ref<'A' | 'B'>('A')

const contentKey = computed(() => value.value)

function toggle() {
  value.value = value.value === 'A' ? 'B' : 'A'
}
</script>

<template>
  <div class="tx-demo tx-demo__col" style="gap: 12px; width: 520px;">
    <TxCard variant="plain" background="mask" :padding="14" :radius="14">
      <div class="tx-demo__row" style="gap: 10px; flex-wrap: wrap; align-items: center;">
        <label class="tx-demo__row" style="gap: 8px;">
          <span class="tx-demo__label">preset</span>
          <TuffSelect v-model="preset" style="min-width: 180px;">
            <TuffSelectItem value="fade" label="fade" />
            <TuffSelectItem value="slide-fade" label="slide-fade" />
            <TuffSelectItem value="rebound" label="rebound" />
            <TuffSelectItem value="smooth-size" label="smooth-size" />
          </TuffSelect>
        </label>

        <TxButton size="small" type="primary" @click="toggle">
          Toggle
        </TxButton>

        <div style="opacity: 0.75; font-size: 12px;">
          key: <b>{{ contentKey }}</b>
        </div>
      </div>
    </TxCard>

    <TxCard variant="plain" background="mask" :padding="14" :radius="14" style="width: 100%;">
      <TxTransition :preset="preset" :duration="220" mode="out-in">
        <div :key="contentKey" style="padding: 10px 12px;">
          <div style="font-weight: 600; margin-bottom: 8px;">
            Panel {{ value }}
          </div>
          <div
            :style="{
              height: value === 'A' ? '90px' : '180px',
              borderRadius: '12px',
              background: value === 'A'
                ? 'color-mix(in srgb, var(--tx-color-primary, #409eff) 12%, transparent)'
                : 'color-mix(in srgb, var(--tx-color-success, #67c23a) 12%, transparent)',
            }"
          />
        </div>
      </TxTransition>
    </TxCard>

    <TxCard variant="plain" background="mask" :padding="14" :radius="14" style="width: 100%;">
      <div class="tx-demo__label" style="margin-bottom: 8px;">
        Semantic Components
      </div>

      <div class="tx-demo__row" style="gap: 10px; flex-wrap: wrap;">
        <TxTransitionFade :duration="180" mode="out-in">
          <div :key="`fade-${contentKey}`" style="padding: 8px 10px; border-radius: 12px; border: 1px solid var(--tx-border-color-lighter);">
            Fade {{ value }}
          </div>
        </TxTransitionFade>

        <TxTransitionSlideFade :duration="180" mode="out-in">
          <div :key="`slide-${contentKey}`" style="padding: 8px 10px; border-radius: 12px; border: 1px solid var(--tx-border-color-lighter);">
            SlideFade {{ value }}
          </div>
        </TxTransitionSlideFade>

        <TxTransitionRebound :duration="200" mode="out-in">
          <div :key="`rebound-${contentKey}`" style="padding: 8px 10px; border-radius: 12px; border: 1px solid var(--tx-border-color-lighter);">
            Rebound {{ value }}
          </div>
        </TxTransitionRebound>
      </div>
    </TxCard>
  </div>
</template>

List Add/Remove (Y)

Transition List

Demo will load when visible.
<script setup lang="ts">
import { computed, ref } from 'vue'

type Preset = 'fade' | 'slide-fade' | 'rebound'

const preset = ref<Preset>('slide-fade')

const seq = ref(3)
const items = ref([
  { id: 'a', text: 'Alpha' },
  { id: 'b', text: 'Beta' },
  { id: 'c', text: 'Gamma' },
])

const list = computed(() => items.value)

function add() {
  seq.value += 1
  items.value.unshift({ id: `${Date.now()}`, text: `New ${seq.value}` })
}

function remove() {
  items.value.shift()
}
</script>

<template>
  <div class="tx-demo tx-demo__col" style="gap: 12px; width: 520px;">
    <TxCard variant="plain" background="mask" :padding="14" :radius="14">
      <div class="tx-demo__row" style="gap: 10px; flex-wrap: wrap; align-items: center;">
        <label class="tx-demo__row" style="gap: 8px;">
          <span class="tx-demo__label">preset</span>
          <TuffSelect v-model="preset" style="min-width: 180px;">
            <TuffSelectItem value="fade" label="fade" />
            <TuffSelectItem value="slide-fade" label="slide-fade" />
            <TuffSelectItem value="rebound" label="rebound" />
          </TuffSelect>
        </label>

        <TxButton size="small" @click="add">
          Add
        </TxButton>
        <TxButton size="small" @click="remove">
          Remove
        </TxButton>
      </div>
    </TxCard>

    <TxCard variant="plain" background="mask" :padding="14" :radius="14" style="width: 100%;">
      <TxTransition :preset="preset" group tag="div" :duration="180" style="display: grid; gap: 10px;">
        <div
          v-for="item in list"
          :key="item.id"
          style="padding: 10px 12px; border-radius: 12px; border: 1px solid var(--tx-border-color-lighter); background: var(--tx-fill-color-blank);"
        >
          {{ item.text }}
        </div>
      </TxTransition>
    </TxCard>
  </div>
</template>

API

TxTransition Props

PropTypeDefaultDescription
preset'fade' | 'slide-fade' | 'rebound' | 'smooth-size''fade'Selects the transition name. smooth-size uses TxTransitionSmoothSize when group=false.
groupbooleanfalseUses Vue TransitionGroup for keyed lists.
tagstring'div'Root tag forwarded to TransitionGroup when group=true.
appearbooleantrueEnables enter motion on initial render.
mode'in-out' | 'out-in''out-in'Vue Transition mode for single-child transitions; ignored by TransitionGroup.
durationnumber180Motion duration in milliseconds, written to --tx-transition-duration.
easingstring'cubic-bezier(0.2, 0, 0, 1)'CSS timing function written to --tx-transition-easing.

Semantic Components

  • TxTransitionFade
  • TxTransitionSlideFade
  • TxTransitionRebound
  • TxTransitionSmoothSize

These components are presets of TxTransition for more semantic usage.