App Setup
After installing the package and importing the CSS, wire up the providers in your application root.
Recommended setup
The recommended entry-point structure nests providers in this order:
src/App.tsx
import React, { useEffect } from "react";
import CssBaseline from "@mui/material/CssBaseline";
import { ThemeProvider as MuiThemeProvider } from "@mui/material/styles";
import { Provider } from "react-redux";
import { CacheProvider } from "@emotion/react";
import { BrowserRouter } from "react-router-dom";
import "@xocialive/ui-components/style.css";
import { getConfig, getEmotionCache } from "@xocialive/ui-components/utils";
import { ErrorBoundary, ConfigLoader } from "@xocialive/ui-components/components";
import { useTheme, useLanguage, AppProvider } from "@xocialive/ui-components/contexts";
import type { PreferencesData } from "@xocialive/ui-components/contexts";
import { store } from "@/store";
import Routes from "@/routes";
const App: React.FC = () => (
<ErrorBoundary level="app">
<ConfigLoader configPath="/config.json">
<Provider store={store}>
<BrowserRouter>
<AppProvider
config={{
fetchPreferences: async () => {
// fetch from your API and return Partial<PreferencesData>
return {};
},
savePreferences: async (preferences) => {
// persist to your API
},
currentApplicationId: "my-app-id",
}}
onPreferencesLoaded={(prefs) => {
// e.g. sync i18next language
}}
>
<ThemedContent />
</AppProvider>
</BrowserRouter>
</Provider>
</ConfigLoader>
</ErrorBoundary>
);
const ThemedContent: React.FC = () => {
const { theme } = useTheme();
const { direction, language } = useLanguage();
const themeWithDirection = React.useMemo(() => ({ ...theme, direction }), [theme, direction]);
const emotionCache = React.useMemo(() => getEmotionCache(direction), [direction]);
return (
<CacheProvider value={emotionCache}>
<MuiThemeProvider theme={themeWithDirection}>
<CssBaseline />
<Routes />
</MuiThemeProvider>
</CacheProvider>
);
};
export default App;
src/main.tsx
import React from "react";
import ReactDOM from "react-dom/client";
import App from "@/App";
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<App />
</React.StrictMode>
);
The provider stack serves these roles:
| Provider | Purpose |
|---|---|
ErrorBoundary | Catches unhandled React errors at the app level |
ConfigLoader | Fetches and validates /config.json, injects it via getConfig() |
Redux Provider | Makes the store (including the toast slice) available |
BrowserRouter | Adds routing context |
AppProvider | Fetches/saves user preferences; wraps ThemeProvider + LanguageProvider |
CacheProvider | Emotion cache with RTL/LTR direction for correct MUI CSS generation |
MuiThemeProvider | Applies the resolved MUI theme with the current direction |
With Redux store integration
toastReducer must be registered under the toast key:
src/store/index.ts
import { configureStore } from "@reduxjs/toolkit";
import { setupListeners } from "@reduxjs/toolkit/query";
import { toastReducer } from "@xocialive/ui-components";
export const store = configureStore({
reducer: {
toast: toastReducer,
// add your own reducers and RTK Query APIs here
},
middleware: (getDefaultMiddleware) => getDefaultMiddleware(),
});
setupListeners(store.dispatch);
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
With i18next integration
Sync the language with i18next inside onPreferencesLoaded and inside ThemedContent:
import i18n from "@/utils/i18n";
<AppProvider
config={{ fetchPreferences, savePreferences, currentApplicationId }}
onPreferencesLoaded={(prefs) => {
if (prefs.language) i18n.changeLanguage(prefs.language);
}}
>
<ThemedContent />
</AppProvider>;
Inside ThemedContent, keep document.documentElement.lang in sync:
const ThemedContent: React.FC = () => {
const { language } = useLanguage();
useEffect(() => {
document.documentElement.lang = language;
i18n.changeLanguage(language);
}, [language]);
// ...
};