diff --git a/docs/.env b/docs/.env
index e79e6f46e8e1a3..f0fe34e156684a 100644
--- a/docs/.env
+++ b/docs/.env
@@ -1,2 +1,6 @@
+BUILD_ONLY_ENGLISH_LOCALE=true
FEEDBACK_URL=https://hgvi836wi8.execute-api.us-east-1.amazonaws.com
-NEXT_PUBLIC_MUI_CHAT_API_BASE_URL=https://chat-backend.mui.com
\ No newline at end of file
+GITHUB_TEMPLATE_DOCS_FEEDBACK=4.docs-feedback.yml
+NEXT_PUBLIC_MUI_CHAT_API_BASE_URL=https://chat-backend.mui.com
+SOURCE_CODE_REPO=https://github.com/mui/material-ui
+SOURCE_GITHUB_BRANCH=master
diff --git a/docs/README.md b/docs/README.md
index e564a475ff68fe..d9793311de3d81 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -17,7 +17,6 @@ Package managers other than pnpm (like npm or Yarn) are not supported and will n
[You can follow this guide](https://github.com/mui/material-ui/blob/HEAD/CONTRIBUTING.md)
on how to get started contributing to MUI.
-## How do I help to improve the translations?
+## Translations
-Please visit https://crowdin.com/project/material-ui-docs where you will be able to select a language and edit the translations.
-Please don't submit pull requests directly.
+Are currently disabled https://github.com/mui/material-ui/issues/33445
diff --git a/docs/app/appWrapper.tsx b/docs/app/appWrapper.tsx
new file mode 100644
index 00000000000000..f4c91c9b07fdf8
--- /dev/null
+++ b/docs/app/appWrapper.tsx
@@ -0,0 +1,329 @@
+'use client';
+import { CodeCopyProvider } from '@mui/docs/CodeCopy';
+import { DocsProvider } from '@mui/docs/DocsProvider';
+import { useRouter } from '@mui/docs/routing';
+import joyPkgJson from '@mui/joy/package.json';
+import materialPkgJson from '@mui/material/package.json';
+import systemPkgJson from '@mui/system/package.json';
+import { LicenseInfo } from '@mui/x-license';
+import docsInfraPages from 'docs/data/docs-infra/pages';
+import generalDocsPages from 'docs/data/docs/pages';
+import joyPages from 'docs/data/joy/pages';
+import materialPages from 'docs/data/material/pages';
+import systemPages from 'docs/data/system/pages';
+import SvgMuiLogomark, {
+ muiSvgLogoString,
+ muiSvgWordmarkString,
+} from 'docs/src/icons/SvgMuiLogomark';
+import GoogleAnalytics from 'docs/src/modules/components/GoogleAnalytics';
+import PageContext from 'docs/src/modules/components/PageContext';
+import { ThemeProvider } from 'docs/src/modules/components/ThemeContext';
+import { CodeVariantProvider } from 'docs/src/modules/utils/codeVariant';
+import findActivePage from 'docs/src/modules/utils/findActivePage';
+import getProductInfoFromUrl from 'docs/src/modules/utils/getProductInfoFromUrl';
+import { pathnameToLanguage } from 'docs/src/modules/utils/helpers';
+import { defaultLanguage, getTranslations } from 'docs/src/modules/utils/i18n';
+import DocsStyledEngineProvider from 'docs/src/modules/utils/StyledEngineProviderApp';
+import { loadCSS } from 'fg-loadcss';
+import * as React from 'react';
+import ReactDOM from 'react-dom';
+import * as config from '../config';
+
+interface Props {
+ children: React.ReactNode;
+ userLanguage: string;
+}
+
+// Remove the license warning from demonstration purposes
+LicenseInfo.setLicenseKey(process.env.NEXT_PUBLIC_MUI_LICENSE!);
+
+let reloadInterval: number;
+
+// Avoid infinite loop when "Upload on reload" is set in the Chrome sw dev tools.
+function lazyReload() {
+ window.clearInterval(reloadInterval);
+ reloadInterval = window.setInterval(() => {
+ if (document.hasFocus()) {
+ window.location.reload();
+ }
+ }, 100);
+}
+
+// Inspired by
+// https://developers.google.com/web/tools/workbox/guides/advanced-recipes#offer_a_page_reload_for_users
+function forcePageReload(registration: ServiceWorkerRegistration) {
+ if (!navigator.serviceWorker.controller) {
+ // The window client isn't currently controlled so it's a new service
+ // worker that will activate immediately.
+ return;
+ }
+
+ if (registration.waiting) {
+ // SW is waiting to activate. Can occur if multiple clients open and
+ // one of the clients is refreshed.
+ registration.waiting.postMessage('skipWaiting');
+ return;
+ }
+
+ function listenInstalledStateChange() {
+ registration.installing!.addEventListener('statechange', (event) => {
+ const target = event.target as unknown as { state: string };
+
+ if (target.state === 'installed' && registration.waiting) {
+ // A new service worker is available, inform the user
+ registration.waiting.postMessage('skipWaiting');
+ } else if (target.state === 'activated') {
+ // Force the control of the page by the activated service worker.
+ lazyReload();
+ }
+ });
+ }
+
+ if (registration.installing) {
+ listenInstalledStateChange();
+ return;
+ }
+
+ // We are currently controlled so a new SW may be found...
+ // Add a listener in case a new SW is found,
+ registration.addEventListener('updatefound', listenInstalledStateChange);
+}
+
+async function registerServiceWorker() {
+ if (
+ 'serviceWorker' in navigator &&
+ process.env.NODE_ENV === 'production' &&
+ window.location.host.includes('mui.com')
+ ) {
+ // register() automatically attempts to refresh the sw.js.
+ const registration = await navigator.serviceWorker.register('/sw.js');
+ forcePageReload(registration);
+ }
+}
+
+let dependenciesLoaded = false;
+
+function loadDependencies() {
+ if (dependenciesLoaded) {
+ return;
+ }
+
+ dependenciesLoaded = true;
+
+ loadCSS(
+ 'https://fonts.googleapis.com/icon?family=Material+Icons|Material+Icons+Two+Tone',
+ document.querySelector('#material-icon-font') as HTMLElement,
+ );
+}
+
+/**
+ * Preconnect allows the browser to setup early connections before an HTTP request
+ is actually sent to the server.
+ This includes DNS lookups, TLS negotiations, TCP handshakes.
+ */
+function preconnectResources() {
+ ReactDOM.preconnect('https://fonts.gstatic.com', { crossOrigin: 'anonymous' });
+ ReactDOM.preconnect('https://fonts.googleapis.com');
+}
+
+if (typeof window !== 'undefined' && process.env.NODE_ENV === 'production') {
+ // eslint-disable-next-line no-console
+ console.log(
+ `%c
+
+███╗ ███╗ ██╗ ██╗ ██████╗
+████╗ ████║ ██║ ██║ ██╔═╝
+██╔████╔██║ ██║ ██║ ██║
+██║╚██╔╝██║ ██║ ██║ ██║
+██║ ╚═╝ ██║ ╚██████╔╝ ██████╗
+╚═╝ ╚═╝ ╚═════╝ ╚═════╝
+
+Tip: you can access the documentation \`theme\` object directly in the console.
+`,
+ 'font-family:monospace;color:#1976d2;font-size:12px;',
+ );
+}
+
+export default function AppWrapper(props: Props) {
+ const { children, userLanguage } = props;
+
+ const router = useRouter();
+ const translations = getTranslations();
+
+ // TODO move productId & productCategoryId resolution to page layout.
+ // We should use the productId field from the markdown and fallback to getProductInfoFromUrl()
+ // if not present
+ const { productId, productCategoryId } = getProductInfoFromUrl(router.pathname);
+
+ React.useEffect(() => {
+ loadDependencies();
+ registerServiceWorker();
+ preconnectResources();
+
+ // Remove the server-side injected CSS.
+ const jssStyles = document.querySelector('#jss-server-side');
+ if (jssStyles) {
+ jssStyles.parentElement!.removeChild(jssStyles);
+ }
+ }, []);
+
+ const productIdentifier = React.useMemo(() => {
+ const languagePrefix = userLanguage === defaultLanguage ? '' : `/${userLanguage}`;
+
+ if (productId === 'material-ui') {
+ return {
+ metadata: '',
+ name: 'Material UI',
+ logo: SvgMuiLogomark,
+ logoSvg: muiSvgLogoString,
+ wordmarkSvg: muiSvgWordmarkString,
+ versions: [
+ { text: `v${materialPkgJson.version}`, current: true },
+ {
+ text: 'v6',
+ href: `https://v6.mui.com${languagePrefix}/material-ui/getting-started/`,
+ },
+ {
+ text: 'v5',
+ href: `https://v5.mui.com${languagePrefix}/getting-started/installation/`,
+ },
+ {
+ text: 'v4',
+ href: `https://v4.mui.com${languagePrefix}/getting-started/installation/`,
+ },
+ {
+ text: 'View all versions',
+ href: `https://mui.com${languagePrefix}/versions/`,
+ },
+ ],
+ };
+ }
+
+ if (productId === 'joy-ui') {
+ return {
+ metadata: '',
+ name: 'Joy UI',
+ logo: SvgMuiLogomark,
+ logoSvg: muiSvgLogoString,
+ wordmarkSvg: muiSvgWordmarkString,
+ versions: [{ text: `v${joyPkgJson.version}`, current: true }],
+ };
+ }
+
+ if (productId === 'system') {
+ return {
+ metadata: '',
+ name: 'MUI System',
+ logo: SvgMuiLogomark,
+ logoSvg: muiSvgLogoString,
+ wordmarkSvg: muiSvgWordmarkString,
+ versions: [
+ { text: `v${systemPkgJson.version}`, current: true },
+ { text: 'v6', href: `https://v6.mui.com${languagePrefix}/system/getting-started/` },
+ { text: 'v5', href: `https://v5.mui.com${languagePrefix}/system/getting-started/` },
+ { text: 'v4', href: `https://v4.mui.com${languagePrefix}/system/basics/` },
+ {
+ text: 'View all versions',
+ href: `https://mui.com${languagePrefix}/versions/`,
+ },
+ ],
+ };
+ }
+
+ if (productId === 'docs-infra') {
+ return {
+ metadata: '',
+ name: 'Docs-infra',
+ logo: SvgMuiLogomark,
+ logoSvg: muiSvgLogoString,
+ wordmarkSvg: muiSvgWordmarkString,
+ versions: [
+ {
+ text: 'v0.0.0',
+ href: `https://mui.com${languagePrefix}/versions/`,
+ },
+ ],
+ };
+ }
+
+ if (productId === 'docs') {
+ return {
+ metadata: '',
+ name: 'Home docs',
+ logo: SvgMuiLogomark,
+ logoSvg: muiSvgLogoString,
+ wordmarkSvg: muiSvgWordmarkString,
+ versions: [
+ {
+ text: 'v0.0.0',
+ href: `https://mui.com${languagePrefix}/versions/`,
+ },
+ ],
+ };
+ }
+
+ return null;
+ }, [userLanguage, productId]);
+
+ const pageContextValue = React.useMemo(() => {
+ let pages = generalDocsPages;
+ if (productId === 'material-ui') {
+ pages = materialPages;
+ } else if (productId === 'joy-ui') {
+ pages = joyPages;
+ } else if (productId === 'system') {
+ pages = systemPages;
+ } else if (productId === 'docs-infra') {
+ pages = docsInfraPages;
+ }
+
+ const { activePage, activePageParents } = findActivePage([...pages], router.pathname);
+
+ return {
+ activePage,
+ activePageParents,
+ pages: [...pages],
+ productIdentifier: productIdentifier!,
+ productId,
+ productCategoryId,
+ };
+ }, [productId, productCategoryId, productIdentifier, router.pathname]);
+
+ let fonts: string[] = [
+ 'https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Roboto:ital,wght@0,300;0,400;0,500;0,700;1,400&display=swap',
+ ];
+ if (pathnameToLanguage(router.pathname).canonicalAs.match(/onepirate/)) {
+ fonts = [
+ 'https://fonts.googleapis.com/css2?family=Roboto+Condensed:wght@700&family=Work+Sans:wght@300;400&display=swap',
+ ];
+ }
+
+ return (
+
+ {fonts.map((font) => (
+
+ ))}
+
+
+
+
+
+
+
+
+ {children}
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/docs/app/custom404.tsx b/docs/app/custom404.tsx
new file mode 100644
index 00000000000000..281b7df0aaf647
--- /dev/null
+++ b/docs/app/custom404.tsx
@@ -0,0 +1,21 @@
+'use client';
+import Divider from '@mui/material/Divider';
+import BrandingCssVarsProvider from 'docs/src/BrandingCssVarsProvider';
+import AppHeaderBanner from 'docs/src/components/banner/AppHeaderBanner';
+import NotFoundHero from 'docs/src/components/NotFoundHero';
+import AppFooter from 'docs/src/layouts/AppFooter';
+import AppHeader from 'docs/src/layouts/AppHeader';
+
+export default function Custom404() {
+ return (
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/docs/app/global.css b/docs/app/global.css
new file mode 100644
index 00000000000000..74d496b6e3b1c7
--- /dev/null
+++ b/docs/app/global.css
@@ -0,0 +1,133 @@
+@import 'tailwindcss/theme.css' layer(theme);
+@import 'tailwindcss/utilities.css' layer(utilities);
+@config '../tailwind.config.mjs';
+
+/*
+ Loads General Sans: Regular (400), Medium (500), SemiBold (600), Bold (700)
+ Typeface documentation: https://www.fontshare.com/fonts/general-sans
+ use https://cssminifier.com/ to minify
+*/
+@font-face {
+ font-family: 'General Sans';
+ src:
+ url(/static/fonts/GeneralSans-Regular.woff2) format('woff2'),
+ url(/static/fonts/GeneralSans-Regular.ttf) format('truetype');
+ font-weight: 400;
+ font-style: normal;
+ font-display: swap;
+}
+@font-face {
+ font-family: 'General Sans';
+ src:
+ url(/static/fonts/GeneralSans-Medium.woff2) format('woff2'),
+ url(/static/fonts/GeneralSans-Medium.ttf) format('truetype');
+ font-weight: 500;
+ font-style: normal;
+ font-display: swap;
+}
+@font-face {
+ font-family: 'General Sans';
+ src:
+ url(/static/fonts/GeneralSans-SemiBold.woff2) format('woff2'),
+ url(/static/fonts/GeneralSans-SemiBold.ttf) format('truetype');
+ font-weight: 600;
+ font-style: normal;
+ font-display: swap;
+}
+@font-face {
+ font-family: 'General Sans';
+ src:
+ url(/static/fonts/GeneralSans-Bold.woff2) format('woff2'),
+ url(/static/fonts/GeneralSans-Bold.ttf) format('truetype');
+ font-weight: 700;
+ font-style: normal;
+ font-display: swap;
+}
+
+/*
+ Loads IBM Plex Sans: 400,500,700 & IBM Plex Mono: 400, 600
+ use https://cssminifier.com/ to minify
+*/
+@font-face {
+ font-family: 'IBM Plex Sans';
+ src:
+ url(/static/fonts/IBMPlexSans-Regular.woff2) format('woff2'),
+ url(/static/fonts/IBMPlexSans-Regular.woff) format('woff'),
+ url(/static/fonts/IBMPlexSans-Regular.ttf) format('truetype');
+ font-weight: 400;
+ font-style: normal;
+ font-display: swap;
+}
+@font-face {
+ font-family: 'IBM Plex Sans';
+ src:
+ url(/static/fonts/IBMPlexSans-Medium.woff2) format('woff2'),
+ url(/static/fonts/IBMPlexSans-Medium.woff) format('woff'),
+ url(/static/fonts/IBMPlexSans-Medium.ttf) format('truetype');
+ font-weight: 500;
+ font-style: normal;
+ font-display: swap;
+}
+@font-face {
+ font-family: 'IBM Plex Sans';
+ src:
+ url(/static/fonts/IBMPlexSans-SemiBold.woff2) format('woff2'),
+ url(/static/fonts/IBMPlexSans-SemiBold.woff) format('woff'),
+ url(/static/fonts/IBMPlexSans-SemiBold.ttf) format('truetype');
+ font-weight: 600;
+ font-style: normal;
+ font-display: swap;
+}
+@font-face {
+ font-family: 'IBM Plex Sans';
+ src:
+ url(/static/fonts/IBMPlexSans-Bold.woff2) format('woff2'),
+ url(/static/fonts/IBMPlexSans-Bold.woff) format('woff'),
+ url(/static/fonts/IBMPlexSans-Bold.ttf) format('truetype');
+ font-weight: 700;
+ font-style: normal;
+ font-display: swap;
+}
+
+/* First SSR paint */
+.only-light-mode {
+ display: 'block';
+}
+.only-dark-mode {
+ display: 'none';
+}
+
+/* Post SSR Hydration */
+.mode-dark .only-light-mode {
+ display: 'none';
+}
+.mode-dark .only-dark-mode {
+ display: 'block';
+}
+
+/* TODO migrate to .only-dark-mode to .only-dark-mode-v2 */
+[data-mui-color-scheme='light'] .only-dark-mode-v2 {
+ display: 'none';
+}
+[data-mui-color-scheme='dark'] .only-light-mode-v2 {
+ display: 'none';
+}
+
+.plan-pro,
+.plan-premium {
+ display: 'inline-block';
+ height: '0.9em';
+ width: '1em';
+ vertical-align: 'middle';
+ margin-left: '0.3em';
+ margin-bottom: '0.08em';
+ background-size: 'contain';
+ background-repeat: 'no-repeat';
+ flex-shrink: 0;
+}
+.plan-pro {
+ background-image: 'url(/static/x/pro.svg)';
+}
+.plan-premium {
+ background-image: 'url(/static/x/premium.svg)';
+}
diff --git a/docs/pages/index.tsx b/docs/app/home.tsx
similarity index 59%
rename from docs/pages/index.tsx
rename to docs/app/home.tsx
index 0bb1798a14d507..32342f7ea41537 100644
--- a/docs/pages/index.tsx
+++ b/docs/app/home.tsx
@@ -1,50 +1,46 @@
-import * as React from 'react';
-import NoSsr from '@mui/material/NoSsr';
+'use client';
import Divider from '@mui/material/Divider';
-import Head from 'docs/src/modules/components/Head';
-import AppHeader from 'docs/src/layouts/AppHeader';
+import NoSsr from '@mui/material/NoSsr';
+import BrandingCssVarsProvider from 'docs/src/BrandingCssVarsProvider';
+import AppHeaderBanner from 'docs/src/components/banner/AppHeaderBanner';
+import DesignSystemComponents from 'docs/src/components/home/DesignSystemComponents';
import Hero from 'docs/src/components/home/Hero';
-import References, { CORE_CUSTOMERS } from 'docs/src/components/home/References';
+import HeroEnd from 'docs/src/components/home/HeroEnd';
+import NewsletterToast from 'docs/src/components/home/NewsletterToast';
import ProductSuite from 'docs/src/components/home/ProductSuite';
-import ValueProposition from 'docs/src/components/home/ValueProposition';
-import DesignSystemComponents from 'docs/src/components/home/DesignSystemComponents';
-import Testimonials from 'docs/src/components/home/Testimonials';
+import References, { CORE_CUSTOMERS } from 'docs/src/components/home/References';
import Sponsors from 'docs/src/components/home/Sponsors';
-import HeroEnd from 'docs/src/components/home/HeroEnd';
+import Testimonials from 'docs/src/components/home/Testimonials';
+import ValueProposition from 'docs/src/components/home/ValueProposition';
import AppFooter from 'docs/src/layouts/AppFooter';
-import BrandingCssVarsProvider from 'docs/src/BrandingCssVarsProvider';
-import NewsletterToast from 'docs/src/components/home/NewsletterToast';
-import AppHeaderBanner from 'docs/src/components/banner/AppHeaderBanner';
+import AppHeader from 'docs/src/layouts/AppHeader';
+import { Suspense } from 'react';
export default function Home() {
return (
-
-
-
+
-
+
+
+
diff --git a/docs/app/layout.tsx b/docs/app/layout.tsx
new file mode 100644
index 00000000000000..f64df8a5726fd6
--- /dev/null
+++ b/docs/app/layout.tsx
@@ -0,0 +1,115 @@
+import 'docs/src/modules/components/bootstrap';
+// --- Post bootstrap -----
+import { getMetaThemeColor } from '@mui/docs/branding';
+import JoyInitColorSchemeScript from '@mui/joy/InitColorSchemeScript';
+import MuiInitColorSchemeScript from '@mui/material/InitColorSchemeScript';
+import { GenerateMetadataProps } from 'docs/src/modules/utils/createMetadata';
+import { defaultLanguage } from 'docs/src/modules/utils/i18n';
+import { Metadata, Viewport } from 'next';
+import Script from 'next/script';
+import * as React from 'react';
+import '../public/static/components-gallery/base-theme.css';
+import AppWrapper from './appWrapper';
+import './global.css';
+
+const PRODUCTION_GA =
+ process.env.NEXT_PUBLIC_DEPLOY_ENV === 'production' ||
+ process.env.NEXT_PUBLIC_DEPLOY_ENV === 'staging';
+
+const GOOGLE_ANALYTICS_ID_V4 = PRODUCTION_GA ? 'G-5NXDQLC2ZK' : 'G-XJ83JQEK7J';
+
+export const viewport: Viewport = {
+ // PWA primary color
+ themeColor: [
+ { media: '(prefers-color-scheme: light)', color: getMetaThemeColor('light') },
+ { media: '(prefers-color-scheme: dark)', color: getMetaThemeColor('dark') },
+ ],
+};
+
+export async function generateMetadata(props: GenerateMetadataProps): Promise {
+ return {
+ icons: {
+ apple: { sizes: '180x180', url: '/static/icons/180x180.png' }, // iOS Icon
+ icon: '/static/favicon.ico',
+ },
+ /*
+ manifest.json provides metadata used when your web app is added to the
+ homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
+ */
+ manifest: '/static/manifest.json',
+ };
+}
+
+export default async function RootLayout({
+ children,
+ params,
+}: {
+ children: React.ReactNode;
+ params: Promise<{ lang?: string }>;
+}) {
+ const { lang } = await params;
+ const userLanguage = lang ?? defaultLanguage;
+
+ return (
+
+
+ {/* ========== Font preload (prevent font flash) ============= */}
+ 6kb)
+ href="/static/fonts/GeneralSans-Semibold-subset.woff2"
+ as="font"
+ type="font/woff2"
+ crossOrigin="anonymous"
+ />
+