react-native-palette-colors
v1.0.2
Published
High-performance native color palette extraction for React Native. No Expo required. Wraps Google Palette API (Android) and CoreImage (iOS).
Maintainers
Readme
react-native-palette-colors
High-performance, purely native color palette extraction for React Native.
No Expo required. No JavaScript image processing. Zero external dependencies.
Why This Package Exists
The most popular color extraction library for React Native — react-native-image-colors — has a hard dependency on expo-modules-core. This causes fatal runtime crashes on bare React Native 0.76+ projects where the New Architecture is enabled:
TypeError: Cannot read property 'EventEmitter' of undefinedSince React Native 0.82+ makes the New Architecture mandatory, the old bridge-based libraries are permanently broken for bare workflows.
react-native-palette-colors is a lightweight, zero-dependency alternative that wraps the exact same native APIs used by Spotify and Netflix:
- Android: Google's Palette API — pixel-cluster-based color quantization
- iOS: CoreImage CIAreaAverage — hardware-accelerated color sampling
How It Compares
| Feature | react-native-palette-colors | react-native-image-colors | rn-color-thief |
|---|---|---|---|
| Expo Required | ❌ No | ✅ Yes | ❌ No |
| RN 0.76+ New Arch | ✅ Works | ❌ Crashes | ✅ Works |
| Extra Dependencies | 0 | expo-modules-core | @shopify/react-native-skia (~5MB) |
| Android Engine | Google Palette API | Google Palette API | Skia |
| iOS Engine | CoreImage | UIImageColors | Skia |
| Swatches Returned | 7 | 6 | Configurable |
| Base64 Support | ✅ | ❌ | ✅ |
| Smart Fallback Cascade | ✅ Native | ❌ Manual | ❌ Manual |
| Bundle Size Impact | ~15KB | ~200KB+ | ~5MB+ |
Installation
npm install react-native-palette-colors
# or
yarn add react-native-palette-colorsiOS
cd ios && pod installAndroid
No additional setup — autolinking handles everything.
Minimum Requirements: React Native ≥ 0.71, iOS ≥ 13.0, Android SDK ≥ 24
Quick Start
import { getColors } from 'react-native-palette-colors';
const colors = await getColors('https://example.com/album-cover.jpg', {
fallback: '#1A1A2E',
});
console.log(colors.dominant); // '#D82020'
console.log(colors.darkMuted); // '#2A0808'
console.log(colors.vibrant); // '#FF2424'
console.log(colors.lightVibrant); // '#FF8080'API Reference
getColors(url, config?)
Extracts prominent colors from an image source.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| url | string | ✅ | Image source (see Supported Sources) |
| config | ImageColorsConfig | ❌ | Optional configuration |
Config Options:
| Option | Type | Default | Description |
|---|---|---|---|
| fallback | string | — | Hex color to use if extraction fails. If provided, the promise always resolves (never rejects). |
Returns: Promise<ImageColorsResult>
ImageColorsResult
| Property | Type | Description |
|---|---|---|
| dominant | string | Primary dominant color of the artwork |
| vibrant | string | Brightest, most saturated accent color |
| darkVibrant | string | Rich dark accent — great for dark theme gradients |
| darkMuted | string | Subdued dark tone — ideal for background gradients |
| muted | string | Desaturated mid-tone — subtle backgrounds |
| lightVibrant | string | Bright pastel accent — light theme highlights |
| lightMuted | string | Soft light tone — light theme backgrounds |
| platform | 'android' \| 'ios' | Platform that performed extraction |
| dominantPopulation | number | Pixel count for dominant swatch (Android) |
| vibrantPopulation | number | Pixel count for vibrant swatch (Android) |
Supported Sources
| Source Type | Format | Example |
|---|---|---|
| Remote URL | http:// or https:// | 'https://example.com/cover.png' |
| Local File | file:// | 'file:///path/to/image.jpg' |
| Base64 | data:image/...;base64,... | 'data:image/png;base64,iVBOR...' |
| Content Provider | content:// (Android) | 'content://media/external/images/123' |
| Bundled Drawable | resource name (Android) | 'ic_launcher' |
| RN Asset | Image.resolveAssetSource() | See React Native Assets |
React Native Assets
For images loaded via require(), resolve them first:
import { Image } from 'react-native';
const asset = require('./assets/cover.png');
const uri = Image.resolveAssetSource(asset).uri;
const colors = await getColors(uri);Smart Fallback Cascade
Unlike other libraries that return #000000 when a swatch isn't found, react-native-palette-colors implements a native cascade on the C++/Kotlin/Swift thread:
darkMuted → dominant → vibrant → fallback
muted → darkMuted → dominant → fallback
lightMuted → muted → dominant → fallbackThis guarantees that no color slot is ever pitch black unless the image itself is black.
Usage Examples
Dynamic Gradient Background (Spotify/Netflix Style)
import React, { useEffect, useState } from 'react';
import { View } from 'react-native';
import LinearGradient from 'react-native-linear-gradient';
import { getColors, ImageColorsResult } from 'react-native-palette-colors';
function AlbumScreen({ coverUrl }: { coverUrl: string }) {
const [colors, setColors] = useState<ImageColorsResult | null>(null);
useEffect(() => {
getColors(coverUrl, { fallback: '#121212' }).then(setColors);
}, [coverUrl]);
return (
<LinearGradient
colors={[
colors?.darkMuted ?? '#121212',
'#121212',
]}
>
{/* Your content here */}
</LinearGradient>
);
}Adaptive Theme Colors
const colors = await getColors(imageUrl, { fallback: '#1A1A2E' });
const theme = {
background: colors.darkMuted,
surface: colors.muted,
accent: colors.vibrant,
textOnAccent: colors.lightVibrant,
};Architecture
┌──────────────────────────────────────────────┐
│ JavaScript │
│ │
│ getColors(url, config) │
│ │ │
│ ▼ │
│ NativeModules.ImageColorsModule │
└──────────────┬───────────────────────────────┘
│
┌───────┴───────┐
│ │
┌──────▼──────┐ ┌──────▼──────┐
│ Android │ │ iOS │
│ │ │ │
│ Palette │ │ CoreImage │
│ API (24 │ │ CIArea │
│ color │ │ Average │
│ depth) │ │ (4-region │
│ │ │ sampling) │
│ Kotlin │ │ Swift │
│ Coroutines │ │ GCD │
│ (IO thread)│ │ (.userInit)│
└─────────────┘ └─────────────┘Troubleshooting
The package doesn't seem to be linked
- Ensure you ran
pod install(iOS) - Rebuild the app completely (
npx react-native run-android/run-ios) - Do not use Expo Go — this is a native module
Colors look different on Android vs iOS
Android uses Google's Palette API (pixel cluster quantization) while iOS uses CoreImage (region-averaged color sampling). Results will be similar but not pixel-identical. Both produce visually appealing gradients.
Getting all black colors
Your image may be predominantly dark. Use the fallback option to guarantee a usable color:
const colors = await getColors(url, { fallback: '#1A1A2E' });Contributing
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
License
MIT © robinsharaya
