react-seamless-marquee
v1.1.0
Published
A seamless, accessible React marquee with RTL support, dynamic content measurement, and reduced-motion fallback
Maintainers
Readme
react-seamless-marquee
A seamless, accessible React marquee component with RTL support, dynamic content measurement, and reduced-motion fallback.
Built for real-world use cases like overflowing quiz options, ticker text, and Persian/Arabic content.
Features
- Seamless infinite loop — dynamically repeats content to fill any container width with no visible gaps
- RTL support — correct geometry even when the page uses
dir="rtl" - Accessible — screen-reader text,
role="marquee", andprefers-reduced-motionfallback - Responsive — recalculates on resize via
ResizeObserver - Configurable — speed, direction, gap, fade edges, pause on hover/click
- Zero CSS setup — styles are auto-injected; optional CSS import available
Install
npm install react-seamless-marqueeUsage
import { Marquee } from 'react-seamless-marquee';
function App() {
return (
<Marquee rtl speed={80} pauseOnHover playOnlyWhenOverflow={false} ariaLabel="Breaking news">
Breaking news headline goes here
</Marquee>
);
}Optional CSS import
Styles are injected automatically. To load from a stylesheet instead (e.g. for CSP):
import 'react-seamless-marquee/styles.css';Next.js App Router
The package ships with "use client" — import it directly in client components.
Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| children | ReactNode | — | Content to scroll |
| speed | number | 60 | Scroll speed in px/s |
| direction | 'left' \| 'right' | 'left' | Scroll direction |
| pauseOnHover | boolean | true | Pause while hovering |
| pauseOnClick | boolean | false | Toggle pause on click |
| gap | number | 48 | Gap between repeated items (px) |
| fadeEdges | boolean | true | Fade edges with gradient mask |
| rtl | boolean | false | Set dir="rtl" on each item |
| playOnlyWhenOverflow | boolean | true | Only animate when content is wider than the container |
| ariaLabel | string | — | Accessible label |
| className | string | '' | Extra class on root element |
| style | CSSProperties | — | Inline styles on root element |
How it works
- A hidden measurement span calculates the content width.
- The component computes how many copies are needed to fill twice the container width.
- A CSS
translateXanimation loops seamlessly using a calculated--marquee-distance. - The viewport is forced to
direction: ltrso animation math stays correct; individual items can still usedir="rtl"for text.
License
MIT
