expo-agent-spinners: 54 Text-Based Spinners for React Native and Expo
54 terminal-style agent-like spinners for React Native & Expo. Lightweight, zero native dependencies — just Text. No heavy UI threads
At a glance
- What is it?
- A copy-and-paste collection of terminal-style loading indicators built only from Text and setInterval. The trade-off is layout: Unicode glyph widths vary by font, so every spinner needs a fixed-size container.
- Who is it for?
- Adopt expo-agent-spinners if you want a CLI or agent-stream aesthetic without pulling in SVG, Lottie, or native modules, and you are willing to size a fixed container per spinner. Do not adopt it if you need a published npm package with versioned releases, or if your design cannot tolerate font-dependent glyph widths.
- Can I use it commercially?
- Not without permission. GitHub finds no licence file in the repository, and without a licence all rights are reserved by default: you may read the code but not reuse it. Check the README, or ask the authors, before using it.
- Is it still maintained?
- Yes. The repository last received commits 150 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The Problem: Terminal Aesthetics Without Native Dependencies
Most React Native loading indicators arrive as an image sequence, an SVG animation, or a Lottie file. Each of those adds either a binary asset, a native module, or an animation runtime that competes for the UI thread. expo-agent-spinners takes the opposite route: every spinner is a sequence of Unicode characters swapped on a timer, rendered through React Native's Text component. The README puts it as 'just Text and setInterval. No heavy UI threads.'
The target audience is narrow and specific. The README lists AI agent streams, CLI-style UIs, lightweight loading states, and monospace layouts. If you are building an app that shows an LLM generating a response, or a terminal-emulator screen, or a developer tool with a monospace typeface, a braille or ASCII spinner reads as native to that context in a way a spinning arc image does not. If you are building a consumer shopping app, this collection is probably the wrong vocabulary.
How the Spinners Work: Frames, Timers, and Nothing Else
Each spinner is a React component in the src/components/spinners directory. The README's props table shows a shared interface across all 54: size (number, default 24), color (string, default "#fff"), and style (StyleProp<ViewStyle>). The style prop targets an outer container, which tells you the component wraps its Text in a View rather than rendering bare text into the parent layout.
The animation mechanism follows from the stated dependency set. A frame array of strings is held in the component, an interval advances an index, and the current frame is rendered as Text. Because the frames are plain strings, the animation is entirely JavaScript-driven and there is no native side to configure. The README does not publish the frame arrays or the interval duration, so the exact tick rate per spinner cannot be confirmed from the material provided. What can be confirmed is the taxonomy: 32 braille spinners, 15 ASCII, 2 arrow, and 6 emoji, for 54 total. The braille group includes named variants such as dots through dots14, sand, bounce, wave, scan, rain, pulse, snake, sparkle, cascade, columns, orbit, breathe, waverows, checkerboard, helix, fillsweep, and diagswipe. The ASCII group runs from dqpb and rolling_line through arc, balloon, circle_halves, circle_quarters, point, square_corners, toggle, triangle, grow_horizontal, grow_vertical, and noise.
Installation Is a Copy, Not an npm Install
This is the detail that changes how you evaluate the project. The README's installation section does not say npm install expo-agent-spinners. It says: 'You can copy any spinner you need from the src/components/spinners directory for use in your project.' There is no published package referenced anywhere in the supplied material, and the repository has no retrieved releases.
In practice that means cloning the repo and copying the files you want. A usage example imports from a relative path:
import { DotsSpinner } from "./src/components/spinners/dots";
and renders it as <DotsSpinner size={24} color="#fff" style={{ width: 40, height: 40 }} />. The README also mentions cloning the repository and running the Expo demo app to see all 54 spinners live, though it does not list the commands for that demo.
Copying source has consequences worth stating plainly. You own upgrades: there is no version range to bump, so picking up a fix means diffing the upstream file against your copy. You also absorb the import paths, which is why the example uses a relative path rather than a package name. For a project that vendors 54 small components, that is manageable, but it is not the same maintenance posture as a dependency in package.json.
The Layout Constraint: Fixed Containers and Character Widths
The README devotes more space to container sizing than to any other topic, and that is a signal. Spinners render Unicode characters whose pixel width depends on font rendering, so the documentation says to 'always wrap spinners in a fixed-size container' to prevent overflow or shifting.
The README supplies a table mapping character count to recommended container width: single-character spinners such as dots, moon, and arc get width 40; two-character spinners such as dots12, wave, and scan get width 64; three-to-four-character spinners such as point and columns get 80 to 96. It flags multi-character spinners explicitly as wider and warns about clipping.
This is the real cost of the text-only approach. An SVG spinner scales to whatever box you give it. A braille spinner does not: its width is a function of the font size and the glyphs the font actually has. A device that falls back to a different font for a braille codepoint can shift the advance width, and your fixed container is the only thing absorbing that. The README's guidance to use a wider container for multi-character spinners is the project acknowledging the problem rather than solving it.
Where It Breaks Down: Emoji, Fonts, and the Wrong Kind of App
The emoji group is the weakest fit for the stated mechanism. hearts, clock, earth, moon, speaker, and weather render as color emoji on most platforms, and emoji glyph metrics vary more across Android and iOS than monospace braille does. The README's own sizing table is organized by character count, not by glyph class, so an emoji spinner at a given character count may not sit in the same container the table recommends for a braille spinner of the same length. Treat the table as a starting point for emoji, not a guarantee.
The second failure mode is accessibility and motion. Nothing in the supplied material mentions reduced-motion handling, accessibility labels, or a way to pause the interval. If your app must respect a system-level reduce-motion setting, you would be adding that yourself on top of a copied component.
The third case is simply the wrong tool: if you need a spinner that scales cleanly to any size, animates along a path, or matches a brand illustration, a text glyph sequence will not do it. The project is honest about this. Its 'Why text-based?' section lists four use cases, all of which are terminal-adjacent.
Alternatives: react-native-animated-spinkit and Lottie
The most direct alternative in the React Native ecosystem is a prebuilt animated spinner set such as react-native-animated-spinkit, which ships a large library of named spinners rendered as animated SVG paths. The difference in approach is the rendering primitive. Animated SVG spinners are vector shapes with defined geometry, so they scale to any container without a character-width table, and they do not depend on which fonts a device has installed. They also typically require react-native-svg as a peer dependency, which is a native module. That is the trade: predictable geometry and scaling in exchange for a native dependency and a heavier render path.
Lottie is the other common route, and the gap is wider. A Lottie file is a JSON animation played by lottie-react-native, which is a native module with its own build considerations. It gives you designer-authored motion and precise control over easing and timing. It also means an asset pipeline and a dependency that must be kept in step with your React Native version.
expo-agent-spinners sits at the far lightweight end of this spectrum. It has no peer dependency, no asset, and no native module. What it gives up is geometric predictability. If your team already ships react-native-svg for icons, the marginal cost of an SVG spinner library is close to zero, and the container-sizing work disappears. If you are deliberately avoiding native modules, the calculus flips.
License, Maintenance, and What to Verify Before Copying
The README states the project is MIT licensed, credited to eronred. The repository metadata supplied here does not include a license identifier, so the README is the only source for that claim. Before vendoring the code, confirm the LICENSE file exists in the clone. MIT permits commercial use and modification provided the copyright notice and permission notice are retained, but this is a description of the license text, not legal advice; check with your own counsel if the distinction matters to you.
Maintenance cost is dominated by the copy model. There is no changelog in the supplied material and no retrieved releases, so there is no version signal to watch. The last push date is 2026-04-18, which tells you the repository was active recently but says nothing about how often the spinner files change. The practical workflow is to record which files you copied and their source commit, so a future diff is possible.
The first thing to verify is your import surface: the README lists 54 named exports across four categories, and you should confirm each one you plan to use actually exists at the path you expect under src/components/spinners. The second is container sizing per spinner, using the README's character-count table as the baseline. The third is font behavior on your target devices, particularly for the emoji group, where the fixed-container guidance is least likely to hold.
Editorial conclusion
Adopt expo-agent-spinners if you want a CLI or agent-stream aesthetic without pulling in SVG, Lottie, or native modules, and you are willing to size a fixed container per spinner. Do not adopt it if you need a published npm package with versioned releases, or if your design cannot tolerate font-dependent glyph widths. Before committing, verify three things: which spinner entry points you actually import from src/components/spinners, that the container width matches the character count from the README table, and that the MIT license file is present in the repository you clone.
Community notes