Theming in rn-markdown-editor: How It's Built and How to Use It
Previously: Launching the rn-markdown-editor ecosystem and Five themeable UI primitives — Badge, Button, Icons, Input, Skeleton
Every component in this package — Badge, Button, Input, Skeleton, the icon set, and more — pulls its colors from one shared theme system instead of scattering color props across every component. This post walks through how that system is put together and how to wire it into your own app.
The pieces
The theme system is made up of three small files:
theme.ts— defines theThemeColorsshape and ships two ready-made palettes,defaultLightColorsanddefaultDarkColors.ThemeContext.tsx— aThemeProviderthat holds the active theme, persists it, and exposes it via React context.useTheme.ts— a thinuseColors()hook that's the actual entry point components use to read colors.
1. The color tokens (theme.ts)
ThemeColors is a single interface listing every token a component is allowed to ask for — things like background, foreground, primary, border, ring, destructive, warning, and a few brand-specific extras like flameon, fire, and frozen. Because the interface also allows an index signature ([key: string]: string), you can attach extra custom keys beyond the required set without breaking type safety.
defaultLightColors and defaultDarkColors are complete, ready-to-use palettes built on HSL values, so swapping between them is a single object swap — nothing component-level needs to change.
import { defaultLightColors, defaultDarkColors, type ThemeColors } from "rn-markdown-editor";
2. Wiring it up (ThemeContext.tsx)
Wrap your app (or just the part of it using these components) in ThemeProvider:
import { ThemeProvider } from "rn-markdown-editor";
export default function App() {
return (
<ThemeProvider>
<YourApp />
</ThemeProvider>
);
}
By default, ThemeProvider:
- Checks
AsyncStoragefor a previously saved theme and restores it on load. - Falls back to the device's system color scheme if nothing's been saved yet.
- Saves the theme back to
AsyncStoragewhenever it changes, so the choice survives app restarts. - Keeps NativeWind in sync — on web it toggles a
.darkclass on<html>, and on native it calls NativeWind'ssetColorSchemeso anydark:className variants in your own code respond correctly too.
Bringing your own palette
If the defaults aren't a fit, pass lightColors and/or darkColors props with your own full ThemeColors object (plus any extra keys you want):
<ThemeProvider
lightColors={{ ...defaultLightColors, primary: "hsl(260, 70%, 50%)" }}
darkColors={{ ...defaultDarkColors, primary: "hsl(260, 70%, 65%)" }}
>
<YourApp />
</ThemeProvider>
Anything you don't override stays on the built-in defaults for that mode, since the provider only swaps in what you pass.
Controlling the theme
useTheme() gives you direct control if you want a toggle in your own UI:
import { useTheme } from "rn-markdown-editor";
function ThemeToggle() {
const { theme, isDark, toggleTheme, setTheme } = useTheme();
return (
<Button onPress={toggleTheme}>
{isDark ? "Switch to light" : "Switch to dark"}
</Button>
);
}
setTheme("dark") or setTheme("light") lets you set it explicitly — useful for a settings screen with three options (light/dark/system) rather than a simple toggle.
3. Reading colors in components (useTheme.ts)
This is the hook the components themselves — and your own custom components — should reach for:
import { useColors } from "rn-markdown-editor";
function MyCustomChip({ label }: { label: string }) {
const colors = useColors();
return (
<View style={{ backgroundColor: colors.accent, borderRadius: 999 }}>
<Text style={{ color: colors.accentForeground }}>{label}</Text>
</View>
);
}
useColors() just returns whichever palette is currently active from context — light, dark, or your custom override — so there's no separate light/dark branching logic to write yourself.
Quick setup checklist
- Install the package and its peer dependencies (NativeWind,
@react-native-async-storage/async-storage, etc.). - Wrap your app in
<ThemeProvider>— addlightColors/darkColorsonly if you need custom branding. - Use
useColors()inside any component that needs a theme-aware color. - Use
useTheme()wherever you need to toggle or set the theme explicitly.
That's the whole surface area — three files, one provider, one hook.
What's next
This covers the current setup, but it's not the final word on theming here. We're actively working on follow-up updates that will expand configuration options further — including more granular per-component overrides and additional documentation on extending the token set. Keep an eye out for the next post when those land.
System Reliability & Support
The development team remains committed to maintaining a secure, efficient, and highly optimized open-source toolkit. Continuous updates are actively deployed to ensure total cross-platform stability across iOS, Android, and Web deployments. Please cross-reference your project environments and peer packages carefully during initial setup.
For technical assistance or to report rendering anomalies, please submit an issue on our official NPM Project Page.
Thank you for your continued support as we optimize the mobile markdown environment.
Thanks for your time and support. Let’s make Steem great, again.
Learn More About rn-markdown-editor:
Official NPM Link: https://www.npmjs.com/package/rn-markdown-editor
Primary Architecture: TypeScript / JavaScript
Supported Environments: Expo & Bare React Native CLI
Utility Exports: useDebouncedInput, useDisclosure, useMergeState