Skip to main content

App Setup

After installing the package and importing the CSS, wire up the providers in your application root.

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:

ProviderPurpose
ErrorBoundaryCatches unhandled React errors at the app level
ConfigLoaderFetches and validates /config.json, injects it via getConfig()
Redux ProviderMakes the store (including the toast slice) available
BrowserRouterAdds routing context
AppProviderFetches/saves user preferences; wraps ThemeProvider + LanguageProvider
CacheProviderEmotion cache with RTL/LTR direction for correct MUI CSS generation
MuiThemeProviderApplies 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]);

// ...
};

Next steps