Universal Component
TextTransformer
fade + blur `TxAutoSizer` “ + ”
This page was migrated by AI, please review carefully
Migration is complete, but please validate against source code and manual review.
TextTransformer
fade + blur TxAutoSizer “ + ”
Not recommended for high-frequency real-time updates (e.g., streaming text, per-frame state changes). Better for occasional state/title/chapter/short-text changes.
Basic Usage
TextTransformer
Demo will load when visible.
<script setup lang="ts">
import { ref } from 'vue'
const text = ref('Hello')
const duration = ref(320)
const blurPx = ref(10)
const accent = ref(false)
const sizerRef = ref<any>(null)
function toggle() {
void sizerRef.value?.action?.(() => {
text.value = text.value === 'Hello'
? 'Goodbye (blur + fade) - a longer title that will be clipped while resizing'
: 'Hello'
accent.value = !accent.value
})
}
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 12px;">
<div style="display: flex; align-items: center; gap: 12px; flex-wrap: wrap;">
<TxButton @click="toggle">
Toggle
</TxButton>
<div style="display: flex; align-items: center; gap: 10px; flex-wrap: wrap;">
<div style="width: 220px;">
<div style="font-size: 12px; opacity: 0.72; margin-bottom: 6px;">
duration (ms)
</div>
<TxSlider v-model="duration" :min="120" :max="720" :step="10" :show-value="true" />
</div>
<div style="width: 220px;">
<div style="font-size: 12px; opacity: 0.72; margin-bottom: 6px;">
blur (px)
</div>
<TxSlider v-model="blurPx" :min="0" :max="24" :step="1" :show-value="true" />
</div>
</div>
</div>
<TxAutoSizer
ref="sizerRef"
:width="true"
:height="true"
:inline="true"
:duration-ms="duration"
easing="cubic-bezier(0.2, 0, 0, 1)"
outer-class="overflow-hidden"
>
<TxCard variant="plain" background="mask" :padding="12" :radius="14">
<div style="font-size: 14px; font-weight: 600; line-height: 1.4;">
<TxTextTransformer
:text="text"
:duration-ms="duration"
:blur-px="blurPx"
:style="{ color: accent ? 'var(--tx-color-primary)' : 'var(--tx-text-color-primary)' }"
/>
</div>
<div style="font-size: 12px; opacity: 0.75; margin-top: 6px;">
text: {{ text }}
</div>
</TxCard>
</TxAutoSizer>
</div>
</template>
Used with AutoSizer
When you want width/height to follow text changes smoothly, wrap TxTextTransformer in TxAutoSizer and trigger a transaction via autoSizerRef.action(() => ...).
If you do not want text to wrap during size animations (vertical/jumping lines), keep wrap=false; overflow will be clipped (overflow: hidden).
AutoSizer + TextTransformer
Demo will load when visible.
<script setup lang="ts">
import { ref } from 'vue'
const sizerRef = ref<any>(null)
const label = ref('Short')
const accent = ref(false)
const duration = ref(360)
const blurPx = ref(10)
function toggle() {
void sizerRef.value?.action?.(() => {
label.value = label.value === 'Short'
? 'Very very long label (blur + fade) that will be clipped while resizing'
: 'Short'
accent.value = !accent.value
})
}
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 12px;">
<div style="display: flex; align-items: center; gap: 12px; flex-wrap: wrap;">
<TxButton @click="toggle">
Toggle
</TxButton>
<div style="width: 220px;">
<div style="font-size: 12px; opacity: 0.72; margin-bottom: 6px;">
duration (ms)
</div>
<TxSlider v-model="duration" :min="160" :max="720" :step="10" :show-value="true" />
</div>
<div style="width: 220px;">
<div style="font-size: 12px; opacity: 0.72; margin-bottom: 6px;">
blur (px)
</div>
<TxSlider v-model="blurPx" :min="0" :max="24" :step="1" :show-value="true" />
</div>
</div>
<TxAutoSizer
ref="sizerRef"
:width="true"
:height="true"
:inline="true"
:duration-ms="duration"
easing="cubic-bezier(0.2, 0, 0, 1)"
outer-class="overflow-hidden"
>
<TxCard variant="plain" background="mask" :padding="12" :radius="14" style="max-width: 360px;">
<div style="font-size: 13px; line-height: 1.4;">
<TxTextTransformer
:text="label"
:duration-ms="duration"
:blur-px="blurPx"
:style="{ color: accent ? 'var(--tx-color-primary)' : 'var(--tx-text-color-primary)' }"
/>
</div>
</TxCard>
</TxAutoSizer>
</div>
</template>
Long Text / Chapter Switch
Long text chapter
Demo will load when visible.
<script setup lang="ts">
import { ref } from 'vue'
const sizerRef = ref<any>(null)
const long = ref(false)
const duration = ref(380)
const blurPx = ref(12)
const chapterA = `Chapter A\n\nThis is a longer paragraph of text used to simulate chapter content changes.\nIt includes multiple lines so you can observe both width and height transitions.\n\n- Bullet A\n- Bullet B\n- Bullet C\n\nEnd.`
const chapterB = `Chapter B\n\nA different chapter with different length.\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit.\nSed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\n\nUt enim ad minim veniam, quis nostrud exercitation ullamco laboris.\n\nEnd.`
const text = ref(chapterA)
function toggle() {
void sizerRef.value?.action?.(() => {
long.value = !long.value
text.value = long.value ? chapterB : chapterA
})
}
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 12px;">
<div style="display: flex; align-items: center; gap: 12px; flex-wrap: wrap;">
<TxButton @click="toggle">
Toggle chapter
</TxButton>
<div style="width: 220px;">
<div style="font-size: 12px; opacity: 0.72; margin-bottom: 6px;">
duration (ms)
</div>
<TxSlider v-model="duration" :min="180" :max="900" :step="10" :show-value="true" />
</div>
<div style="width: 220px;">
<div style="font-size: 12px; opacity: 0.72; margin-bottom: 6px;">
blur (px)
</div>
<TxSlider v-model="blurPx" :min="0" :max="28" :step="1" :show-value="true" />
</div>
</div>
<TxAutoSizer
ref="sizerRef"
:width="true"
:height="true"
:duration-ms="duration"
easing="cubic-bezier(0.2, 0, 0, 1)"
outer-class="overflow-hidden"
style="max-width: 720px;"
>
<TxCard variant="plain" background="mask" :padding="14" :radius="14">
<div style="font-size: 13px; line-height: 1.6; max-width: 640px;">
<TxTextTransformer :text="text" :duration-ms="duration" :blur-px="blurPx" wrap />
</div>
</TxCard>
</TxAutoSizer>
<div style="font-size: 12px; opacity: 0.65;">
Tip: this component is designed for occasional transitions. Avoid using it for high-frequency real-time updates.
</div>
</div>
</template>
Title + Subtitle
Title + subtitle
Demo will load when visible.
<script setup lang="ts">
import { ref } from 'vue'
const sizerRef = ref<any>(null)
const duration = ref(320)
const blurPx = ref(10)
const accent = ref(false)
const title = ref('Daily Report')
const subtitle = ref('Short summary.')
function toggle() {
void sizerRef.value?.action?.(() => {
if (title.value === 'Daily Report') {
title.value = 'Weekly Report (Longer Title)'
subtitle.value = 'A longer subtitle that spans multiple words.'
}
else {
title.value = 'Daily Report'
subtitle.value = 'Short summary.'
}
accent.value = !accent.value
})
}
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 12px;">
<div style="display: flex; align-items: center; gap: 12px; flex-wrap: wrap;">
<TxButton @click="toggle">
Toggle
</TxButton>
<div style="width: 220px;">
<div style="font-size: 12px; opacity: 0.72; margin-bottom: 6px;">
duration (ms)
</div>
<TxSlider v-model="duration" :min="160" :max="720" :step="10" :show-value="true" />
</div>
<div style="width: 220px;">
<div style="font-size: 12px; opacity: 0.72; margin-bottom: 6px;">
blur (px)
</div>
<TxSlider v-model="blurPx" :min="0" :max="24" :step="1" :show-value="true" />
</div>
</div>
<TxAutoSizer
ref="sizerRef"
:width="true"
:height="true"
:inline="true"
:duration-ms="duration"
easing="cubic-bezier(0.2, 0, 0, 1)"
outer-class="overflow-hidden"
>
<TxCard variant="plain" background="mask" :padding="14" :radius="14" style="max-width: 420px;">
<div style="display: flex; flex-direction: column; gap: 6px;">
<div style="font-size: 14px; font-weight: 700; line-height: 1.3;">
<TxTextTransformer
:text="title"
:duration-ms="duration"
:blur-px="blurPx"
:style="{ color: accent ? 'var(--tx-color-primary)' : 'var(--tx-text-color-primary)' }"
/>
</div>
<div style="font-size: 12px; opacity: 0.8; line-height: 1.4;">
<TxTextTransformer
:text="subtitle"
:duration-ms="duration"
:blur-px="blurPx"
:style="{ color: accent ? 'var(--tx-color-primary)' : 'var(--tx-text-color-secondary)' }"
/>
</div>
</div>
</TxCard>
</TxAutoSizer>
</div>
</template>
Status/Badge Text
Status text
Demo will load when visible.
<script setup lang="ts">
import { ref } from 'vue'
const sizerRef = ref<any>(null)
const duration = ref(280)
const blurPx = ref(10)
const mode = ref<'ok' | 'warn' | 'err'>('ok')
function label() {
if (mode.value === 'ok')
return 'Synced'
if (mode.value === 'warn')
return 'Syncing (may take a while)'
return 'Failed: Network error'
}
function color() {
if (mode.value === 'ok')
return 'var(--tx-color-success)'
if (mode.value === 'warn')
return 'var(--tx-color-warning)'
return 'var(--tx-color-danger)'
}
function toggle() {
void sizerRef.value?.action?.(() => {
mode.value = mode.value === 'ok' ? 'warn' : mode.value === 'warn' ? 'err' : 'ok'
})
}
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 12px;">
<div style="display: flex; align-items: center; gap: 12px; flex-wrap: wrap;">
<TxButton @click="toggle">
Toggle
</TxButton>
<div style="width: 220px;">
<div style="font-size: 12px; opacity: 0.72; margin-bottom: 6px;">
duration (ms)
</div>
<TxSlider v-model="duration" :min="120" :max="600" :step="10" :show-value="true" />
</div>
<div style="width: 220px;">
<div style="font-size: 12px; opacity: 0.72; margin-bottom: 6px;">
blur (px)
</div>
<TxSlider v-model="blurPx" :min="0" :max="24" :step="1" :show-value="true" />
</div>
</div>
<TxAutoSizer
ref="sizerRef"
:width="true"
:height="true"
:inline="true"
:duration-ms="duration"
easing="cubic-bezier(0.2, 0, 0, 1)"
outer-class="overflow-hidden"
>
<TxCard variant="plain" background="mask" :padding="12" :radius="14">
<div style="display: inline-flex; align-items: center; gap: 10px;">
<div
style="width: 8px; height: 8px; border-radius: 99px;"
:style="{ background: color() }"
/>
<TxTextTransformer
:text="label()"
:duration-ms="duration"
:blur-px="blurPx"
:style="{ color: color() }"
/>
</div>
</TxCard>
</TxAutoSizer>
</div>
</template>
API
TxTextTransformer
Props
| Prop | Type | Default | Description |
|---|---|---|---|
text | string | number | - | Value rendered in the current layer and announced through the polite live region. |
durationMs | number | 240 | Transition duration in milliseconds; also controls when the previous layer is removed. |
blurPx | number | 8 | Blur distance applied to the outgoing and incoming layers during the transition. |
tag | string | span | Root HTML tag used for the transformer wrapper. |
wrap | boolean | false | Allows multi-line text by switching layer whitespace from ellipsis mode to pre-line. |