Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/rijvi-mahmud/shaddy/llms.txt

Use this file to discover all available pages before exploring further.

As React applications grow, the root layout typically accumulates a long chain of context providers — auth, theme, i18n, query client, and more. composeProviders flattens that chain into a single, readable component that is easy to extend or reorder without touching JSX structure.

Installation

npx shadcn@latest add https://shaddy-docs.vercel.app/r/compose-providers
You can also copy the source manually. The utility is a single TypeScript file with no runtime dependencies beyond React.

The Provider Hell Problem

Without composeProviders, a typical app root ends up looking like this:
// ❌ Before — deeply nested providers
<AuthProvider>
  <ThemeProvider>
    <LocalizationProvider>
      <QueryClientProvider client={queryClient}>
        <App />
      </QueryClientProvider>
    </LocalizationProvider>
  </ThemeProvider>
</AuthProvider>
Every new provider adds another level of indentation and another file to update. composeProviders collapses this into a flat array:
// ✅ After — a single composed wrapper
import { composeProviders } from '@/utils/compose-providers'
import { AuthProvider } from './auth'
import { ThemeProvider } from './theme'
import { LocalizationProvider } from './localization'
import { QueryClientProvider } from '@tanstack/react-query'

const AppProviders = composeProviders([
  AuthProvider,
  ThemeProvider,
  LocalizationProvider,
  [QueryClientProvider, { client: queryClient }],
])

export default function RootLayout({ children }) {
  return <AppProviders>{children}</AppProviders>
}

Signature

composeProviders(providers, displayName?): React.FC<React.PropsWithChildren<{}>>

ProviderConfig type

Each entry in the providers array is a ProviderConfig, which is either:
  • A plain React component: React.ComponentType<P>
  • A tuple of a component and its props: [React.ComponentType<P>, P]
type ComponentAndProps<P> = [React.ComponentType<P>, P]
type ProviderConfig<P = any> = React.ComponentType<P> | ComponentAndProps<P>
The first provider in the array becomes the outermost wrapper. The implementation reverses the array internally before reducing, so the order you supply matches the visual nesting you’d write by hand.

Parameters

providers
readonly ProviderConfig<any>[]
required
An array of providers to compose. Each entry is either a component or a [Component, props] tuple.
displayName
string
An optional display name for the composed component. Appears in React DevTools, which helps when debugging nested context trees.

Examples

Simple providers (no props)

import { composeProviders } from '@/utils/compose-providers'
import { AuthProvider } from './auth'
import { ThemeProvider } from './theme'
import { LocalizationProvider } from './localization'

const AppProviders = composeProviders(
  [AuthProvider, ThemeProvider, LocalizationProvider],
  'AppProviders' // optional display name
)

// Use at your app root
export default function RootLayout({ children }) {
  return <AppProviders>{children}</AppProviders>
}

Providers with props

Pass a [Component, props] tuple for any provider that requires configuration:
import { composeProviders } from '@/utils/compose-providers'
import { QueryClientProvider } from '@tanstack/react-query'
import { IntlProvider } from 'react-intl'
import { BrowserRouter } from 'react-router-dom'
import { ErrorBoundary } from './error-boundary'
import { queryClient } from './query-client'

const locale = 'en'
const messages = { greeting: 'Hello' }

const AppContainer = composeProviders([
  ErrorBoundary,
  [QueryClientProvider, { client: queryClient }],
  [IntlProvider, { locale, messages }],
  BrowserRouter,
])

export default function Root() {
  return (
    <AppContainer>
      <App />
    </AppContainer>
  )
}
Providers that do not require props are passed as plain component references. Providers that do require props use the tuple form [Provider, props]. Both can be mixed freely in the same array.

Benefits

  • Cleaner code — no more deeply nested provider JSX.
  • Easier maintenance — add, remove, or reorder providers in a single array.
  • Reusable — import AppProviders from one place and use it across tests, Storybook, and your app root.
  • DevTools-friendly — set displayName so the composed component appears legibly in React DevTools.

Build docs developers (and LLMs) love