love-is-love-spinners
v1.0.1
Published
Beautiful, inclusive loading spinners featuring LGBTQ+ pride flags with smooth animations. Framework-agnostic, lightweight, and fully configurable.
Maintainers
Readme
🏳️🌈 love-is-love-spinners
Beautiful, inclusive loading spinners featuring LGBTQ+ pride flags with smooth animations. Framework-agnostic, lightweight, zero dependencies.
Each spinner pulses a pride flag from a tiny dot to full size while rotating clockwise, surrounded by a spinning counter-clockwise text ring. Multiple flags cycle with seamless transitions.
Install
npm install love-is-love-spinnersQuick Start
import { createSpinner } from 'love-is-love-spinners';
// Cycle through ALL pride flags
const spinner = createSpinner('#loading-container');
// When done loading
spinner.destroy();Size Presets
Three built-in sizes, or pass a custom pixel value:
createSpinner('#el', { size: 'sm' }); // 40px — compact, inline use
createSpinner('#el', { size: 'md' }); // 60px — default
createSpinner('#el', { size: 'lg' }); // 90px — hero / splash screens
createSpinner('#el', { size: 120 }); // custom pixel widthRing Text Sayings
Choose from 10 built-in sayings, cycle through all of them, or pass your own:
// Built-in presets
createSpinner('#el', { ringText: 'love-is-love' }); // default
createSpinner('#el', { ringText: 'born-this-way' });
createSpinner('#el', { ringText: 'pride-and-joy' });
createSpinner('#el', { ringText: 'you-are-valid' });
createSpinner('#el', { ringText: 'be-you-be-proud' });
createSpinner('#el', { ringText: 'stronger-together' });
createSpinner('#el', { ringText: 'love-wins' });
createSpinner('#el', { ringText: 'proud-ally' });
createSpinner('#el', { ringText: 'out-and-proud' });
createSpinner('#el', { ringText: 'every-shade-every-soul' });
// Cycle through ALL sayings (changes each pulse)
createSpinner('#el', { ringText: 'cycle' });
// Your own custom text
createSpinner('#el', { ringText: 'PRIDE MONTH 2026' });Ring Text Colors
Six solid presets plus an animated rainbow gradient:
createSpinner('#el', { ringColor: 'white' });
createSpinner('#el', { ringColor: 'black' });
createSpinner('#el', { ringColor: 'gray' }); // default
createSpinner('#el', { ringColor: 'purple' });
createSpinner('#el', { ringColor: 'pink' });
createSpinner('#el', { ringColor: 'gold' });
createSpinner('#el', { ringColor: 'rainbow' }); // animated rainbow gradient!
// Any custom CSS color
createSpinner('#el', { ringColor: '#FF6B6B' });Choose Your Flags
// All 32 flags (default)
createSpinner('#el');
createSpinner('#el', { flags: 'all' });
// Specific flags
createSpinner('#el', { flags: ['rainbow', 'transgender', 'bisexual'] });
// Single flag, no transitions
createSpinner('#el', { flags: ['transgender'] });
// Shuffle the order
createSpinner('#el', { flags: 'all', shuffle: true });Full Configuration
const spinner = createSpinner('#container', {
flags: ['rainbow', 'transgender', 'bisexual', 'pansexual'],
size: 'lg',
speed: 2.5, // seconds per pulse cycle
ringSpeed: 5, // seconds per ring rotation
ringText: 'cycle', // rotate through all sayings
ringColor: 'rainbow', // animated rainbow text
showRing: true,
shuffle: true,
aspectRatio: 0.667, // flag height/width ratio
className: 'my-spinner',
});Control the Spinner
spinner.stop(); // pause animation
spinner.start(); // resume animation
spinner.destroy(); // remove from DOM
spinner.update({ // update options live
speed: 3,
flags: ['lesbian', 'sapphic'],
ringColor: 'pink',
});
spinner.getCurrentFlag(); // e.g. 'rainbow'
spinner.getCurrentRingText(); // e.g. 'LOVE IS LOVE'Framework Examples
Angular
import { Component, ElementRef, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { createSpinner, SpinnerInstance } from 'love-is-love-spinners';
@Component({
selector: 'app-loading',
template: `<div #spinnerEl></div>`,
})
export class LoadingComponent implements OnInit, OnDestroy {
@ViewChild('spinnerEl', { static: true }) spinnerEl!: ElementRef;
private spinner!: SpinnerInstance;
ngOnInit() {
this.spinner = createSpinner(this.spinnerEl.nativeElement, {
flags: ['rainbow', 'transgender'],
size: 'lg',
ringText: 'cycle',
ringColor: 'rainbow',
});
}
ngOnDestroy() {
this.spinner.destroy();
}
}React
import { useEffect, useRef } from 'react';
import { createSpinner } from 'love-is-love-spinners';
function PrideSpinner({ flags = 'all', size = 'md' }) {
const ref = useRef<HTMLDivElement>(null);
useEffect(() => {
if (!ref.current) return;
const spinner = createSpinner(ref.current, { flags, size });
return () => spinner.destroy();
}, [flags, size]);
return <div ref={ref} />;
}Vue
<template>
<div ref="spinnerRef" />
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue';
import { createSpinner } from 'love-is-love-spinners';
const spinnerRef = ref(null);
let spinner;
onMounted(() => {
spinner = createSpinner(spinnerRef.value, {
flags: ['rainbow', 'nonbinary', 'pansexual'],
size: 'lg',
ringColor: 'rainbow',
});
});
onUnmounted(() => spinner?.destroy());
</script>Available Flags (32)
| Key | Name | Key | Name |
|-----|------|-----|------|
| rainbow | Rainbow Pride | gaymen | Gay Men / Vincian |
| progress | Progress Pride | sapphic | Sapphic |
| transgender | Transgender | polyamory | Polyamory |
| bisexual | Bisexual | bear | Bear Pride |
| pansexual | Pansexual | leather | Leather Pride |
| lesbian | Lesbian | bigender | Bigender |
| nonbinary | Non-Binary | pangender | Pangender |
| asexual | Asexual | neutrois | Neutrois |
| aromantic | Aromantic | demiboy | Demiboy |
| intersex | Intersex | demigirl | Demigirl |
| genderfluid | Genderfluid | abrosexual | Abrosexual |
| genderqueer | Genderqueer | aceflux | Aceflux |
| agender | Agender | aroflux | Aroflux |
| demisexual | Demisexual | twospirit | Two-Spirit |
| demiromantic | Demiromantic | queer | Queer |
| polysexual | Polysexual | ally | Straight Ally |
| omnisexual | Omnisexual | | |
Access Flag Data Programmatically
import { FLAGS, ALL_FLAG_KEYS, flagToGradient } from 'love-is-love-spinners';
import { RING_TEXT_PRESETS, ALL_RING_TEXT_KEYS, SIZE_PRESETS } from 'love-is-love-spinners';
console.log(ALL_FLAG_KEYS); // ['rainbow', 'progress', ...]
console.log(ALL_RING_TEXT_KEYS); // ['love-is-love', 'born-this-way', ...]
console.log(SIZE_PRESETS); // { sm: { flagWidth: 40, ... }, ... }
const gradient = flagToGradient(FLAGS.bisexual);Accessibility
role="status"andaria-label="Loading"for screen readers- Hidden screen-reader text announces "Loading..."
- Respects
prefers-reduced-motion— animations are disabled automatically
Browser Support
All modern browsers (Chrome, Firefox, Safari, Edge). Requires ES2020.
Contributing
Contributions welcome! If there's a pride flag we're missing, please open an issue or PR.
When adding a flag, include: the flag key (lowercase), official name, accurate stripe colors (hex, top to bottom), and a brief description.
License
MIT © love-is-love-spinners contributors
🏳️🌈 Love is love. 🏳️⚧️
