React is a leading library for building component-based UIs. Tailwind CSS integrates naturally by allowing styling through utility classes inline, while keeping logic and presentation neatly separated. But as state becomes complex—especially in large apps—it’s essential to scale responsibly. Using React Context alongside Tailwind offers a clean pattern for managing global UI state and styling consistently.
Why Use React Context with Tailwind?
- Manage global UI state like themes, modals, notifications, sidebars
- Automate class application across many components
- Avoid prop drilling and tangled code
- Keep styling declarative and centralized
Context offers a centralized state layer that works beautifully with Tailwind’s utility-first design.
Example: Sidebar Toggle State
Suppose your app has a sidebar that opens/closes:
// SidebarContext.js
import { createContext, useContext, useState } from 'react'
const SidebarContext = createContext()
export function SidebarProvider({ children }) {
const [open, setOpen] = useState(false)
const toggle = () => setOpen((o) => !o)
return (
<SidebarContext.Provider value={{ open, toggle }}>
{children}
</SidebarContext.Provider>
)
}
export const useSidebar = () => useContext(SidebarContext)
Use it in components:
import { useSidebar } from './SidebarContext'
function Sidebar() {
const { open } = useSidebar()
return (
<div className={open ? 'w-64' : 'w-16'} /* plus other Tailwind classes */>
{/* Sidebar content */}
</div>
)
}
Toggle anywhere in the tree:
function ToggleButton() {
const { toggle } = useSidebar()
return (
<button onClick={toggle} className="p-2 bg-indigo-600 text-white rounded">
Toggle Sidebar
</button>
)
}
Example: Notifications via Context
Notifications are another use case:
// NotificationContext.js
import { createContext, useContext, useState } from 'react'
const NotificationContext = createContext()
export function NotificationProvider({ children }) {
const [msgs, setMsgs] = useState([])
const add = (msg) => setMsgs((m) => [...m, msg])
const remove = (i) => setMsgs((m) => m.filter((_, idx) => idx !== i))
return (
<NotificationContext.Provider value={{ msgs, add, remove }}>
{children}
</NotificationContext.Provider>
)
}
export const useNotifications = () => useContext(NotificationContext)
Rendering notifications:
import { useNotifications } from './NotificationContext'
function Alerts() {
const { msgs, remove } = useNotifications()
return (
<div className="fixed top-4 right-4 space-y-2">
{msgs.map((m, i) => (
<div
key={i}
className="bg-green-100 text-green-800 border border-green-300 rounded p-4">
{m.text}
<button onClick={() => remove(i)}>×</button>
</div>
))}
</div>
)
}
Example: Theme Context (Dark Mode)
// ThemeContext.js
import { createContext, useContext, useState, useEffect } from 'react'
const ThemeContext = createContext()
export function ThemeProvider({ children }) {
const [dark, setDark] = useState(false)
useEffect(() => {
document.documentElement.classList.toggle('dark', dark)
}, [dark])
const toggle = () => setDark((d) => !d)
return (
<ThemeContext.Provider value={{ dark, toggle }}>
{children}
</ThemeContext.Provider>
)
}
export const useTheme = () => useContext(ThemeContext)
Use classes like:
function PageLayout() {
const { dark } = useTheme()
return (
<div className={dark ? 'bg-gray-900 text-white' : 'bg-white text-gray-900'}>
{/* Page Content */}
</div>
)
}
Benefits of This Pattern
- Separation of concerns: State lives in context, styling stays inline with Tailwind
- Reusability: Context can be consumed anywhere
- Maintainable UI: Shared visual logic via Tailwind avoids CSS drift
- Scalable: Multi-step forms, dashboards, collaborative tools benefit most
Structure Example
Wrap your app:
import { SidebarProvider } from './SidebarContext'
import { NotificationProvider } from './NotificationContext'
import { ThemeProvider } from './ThemeContext'
function App() {
return (
<SidebarProvider>
<NotificationProvider>
<ThemeProvider>
<PageLayout>
<Sidebar />
<ToggleButton />
<Alerts />
{/* other components */}
</PageLayout>
</ThemeProvider>
</NotificationProvider>
</SidebarProvider>
)
}
Want a Deep Dive?
If you're looking to structure large React projects with Tailwind and Context—covering utility strategies, component patterns, dark mode, and performance—you’ll love my 37-page PDF:
Mastering Tailwind at Scale: Architecture, Patterns & Performance
Grab it now for just $10.
With React Context and Tailwind CSS, you get clean, maintainable UI state and styling — built for scale and clarity.
Top comments (0)