shadcn.io is an independent project built on shadcn/ui
Text
ProIris Text for Vue
Like a camera's iris, a circle grows from each letter's centre to reveal it. For Vue with Ark UI, when a title should be revealed rather than moved.
Iris Text reveals a line a letter at a time, each letter seen through a circle that opens from its centre, like a camera's aperture, until the whole of it shows. The letters never move: they're in place from the first frame, and only what you see of them grows. It plays once, when the text scrolls into view.
Use it for a heading, a product name or a title card with a precise, photographic feel. For letters that slide into place, use Splitting Text; for letters that come into focus from a blur, Blur Text; for letters that unfold, Paper Fold Text. Each letter is clipped by a circle that a CSS keyframe animation opens, delayed by its place in the line, with no animation library; once a letter is open the clip is gone. With reduced motion the text is simply there.
Installation
Usage
<script setup lang="ts">
import { IrisText } from "@/components/ui/iris-text";
</script>
<template>
<h2>
<IrisText text="Picture perfect" />
</h2>
</template>
Demos
Words
by="words" opens each word through one circle, 180 ms apart: for a longer line, and for scripts whose letters join, such as Arabic, which a split between letters would break.
Timing
duration is how long one letter takes to open, 600 ms by default, and stagger the time between one letter and the next, 60 ms. Short ones suit a small label; long ones, a title revealed slowly.
Accessibility
Screen readers read the whole text once, as plain text: the opening letters are hidden from them, and a visually hidden copy carries it. Words wrap whole, and the line keeps its direction on a right-to-left page. With reduced motion every letter is open from the start.
FAQ
When does the animation play?
Once, when at least a quarter of the text is in view: an IntersectionObserver on the text starts it, then stops watching. Pass trigger="mount" to play it as soon as the page shows it, for text that's always on screen.
Does the circle cut off parts of letters?
No. It opens to just past the corners of each letter's box, then the clip is removed altogether, so accents, descenders and the overhang of an italic show whole once a letter is open.
Does the line move while it opens?
No. Each letter is in its place from the start and only its clip changes, so nothing around the text shifts.
What if JavaScript is off or slow to load?
With trigger="view", the server renders the letters closed, waiting, and a page without JavaScript shows the text at once. With trigger="mount" the animation runs from CSS alone, before the page's script loads.
API Reference
IrisText
<span> data-slot="iris-text"
textstring
The text.
by?"characters" | "words"
What opens on its own: each character, or each word (for scripts whose letters join, such as Arabic).
- Type
"characters" | "words"- Default
"characters"
duration?number
How long one character or word takes to open, in milliseconds. @default 600.
stagger?number
The time between one character or word and the next, in milliseconds.
- Default
60 (characters), 180 (words)
trigger?"mount" | "view"
When it plays: as soon as it's on the page, or once it scrolls into view.
- Type
"mount" | "view"- Default
"view"
class?string
Merged with the part's classes.
@complete() โ void
Called once the last character or word is open.
- Returns
void
data-last?stringdata-view?string
"in" when visible is true, otherwise "out".
--iris-text-durationstring
One unit's opening.





