Marquee
v0.0.10
mix mishka.ui.gen.headless marquee
Overview of the Phoenix and LiveView Headless Marquee Component
The Mishka Chelekom Headless Marquee is a Phoenix function component that scrolls a row of content continuously in a LiveView page, with CSS only. There is no hook and no JavaScript. It renders a root div, a track and two group elements. The slot content is drawn in both groups, and the second group is aria-hidden. Because the track holds two identical copies, an animation from translateX(0) to translateX(-50%) loops without a jump.
The component ships no keyframes, speed or direction, so the animation is yours. Style the parts with class on the root (clip the overflow there), track_class on the moving track (animate it there) and group_class on each copy of the content.
Base UI Marquee example - a looping row of names (Phoenix headless)
Base UI Marquee example - a looping row of names (Phoenix headless)
<div class="w-full max-w-80 overflow-hidden">
<.marquee
class="overflow-hidden"
track_class="flex w-max motion-safe:animate-[chelekom-marquee-x_14s_linear_infinite] hover:[animation-play-state:paused]"
group_class="flex shrink-0 items-center gap-6 pr-6 text-sm font-medium text-neutral-700 dark:text-neutral-300"
>
<span>Phoenix</span>
<span>LiveView</span>
<span>Ecto</span>
<span>Oban</span>
<span>Ash</span>
</.marquee>
</div>The keyframes
Define the keyframes in your stylesheet and apply them to the track with track_class. The example above uses an animation named chelekom-marquee-x:
@keyframes chelekom-marquee-x {
from { transform: translateX(0); }
to { transform: translateX(-50%); }
}Moving the track by 50% shifts it by exactly one copy, so the loop restarts where it began. For the join to look even, give each group the same space at its end as between its items, as gap-6 pr-6 does in the example. Swap from and to to reverse the direction, and change the animation duration to change the speed. With Tailwind CSS 4 you can also declare the keyframes inside @theme, next to an --animate-* variable.
Parts & data attributes
Each part carries a stable data-part and a structural chelekom-marquee* class you can target.
| Part | data-part | State / ARIA | Purpose |
|---|---|---|---|
| Root | root | - | Clips the overflow. Add overflow-hidden to its class. |
| Track | track | - | Holds both groups. Apply the animation here. |
| Group | group | aria-hidden="true" on the second copy | The slot content, rendered twice. |
Accessibility
There is no formal ARIA pattern for a marquee. The second copy of the content is aria-hidden, so a screen reader reads it once. Links and buttons stay focusable in the hidden copy, so use the marquee for text and logos and keep controls out of it. Content that moves on its own for more than five seconds should be easy to pause: the example pauses on hover, and you can add a button or a focus rule that does the same.
Attributes
| Name | Type | Default | Values | Required | Description |
|---|---|---|---|---|---|
id
|
string
| — | — | No | Optional unique id |
class
|
any
| — | — | No | Extra classes for the root (clip overflow here) |
track_class
|
any
| — | — | No | Extra classes for the moving track (animate here) |
group_class
|
any
| — | — | No | Extra classes for each content group |
rest
|
global
| — | — | No | — |
Slots
| Name | Required | Description |
|---|---|---|
inner_block
| Yes | The scrolling content |
Options
Each option takes one or more of its values, separated by commas.
| Option | Values |
|---|---|
--type
|
marquee
|
--module
| A module name of your own |
What it generates
mix mishka.ui.gen.headless marquee