- Notifications
You must be signed in to change notification settings - Fork22
MDN's frontend since late 2025, built with Web Components, Lit, and SSR for a fast, clean documentation experience. Fred = /fr(ont)e(n)d/.
License
mdn/fred
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
MDN's next fr(ont)e(n)d.
- Copy
.env-distto.envand update values as needed. The file contains comments for guidance:
cp .env-dist .env
- Install dependencies
npm install - Bring up the dev environment with
npm run start
npm run start- runs the rari server and the live-reloading development server together
- run with
NODE_ENV=productionto run rari with the preview server, you'll need to have runnpm run buildfirst
node --env-file=.env --run rari -- serve- runs the rari server
- necessary for
npm run devandnpm run preview
npm run dev- brings up the live-reloading development server, likely what you want for doing local development
npm run build- builds the production js/css/asset bundles
- must be run at least once for
npm run previewto work
npm run preview- runs the preview server: using the production bundles with the rari server: useful for testing our prod rspack config
If you want to access fred from a different machine, you'll need to run with certain options:
HTTPS=trueto enable HTTPS with a self-signed certificate, allowing Web APIs requiring a secure context to workORIGIN_MAIN=your.local.ip.addressto allowlist your address in the playground
So a full command might look like:
HTTPS=true ORIGIN_MAIN=192.168.0.99 npm run startThis is useful to test changes on mobile, tablets and other platforms.
tl;dr For visitors to MDN, we support theBaseline widely available browser set, with some minor modifications.
TheBaseline widely available browser set is defined as browsers from theCore browser set whose initial release date is on or before 30 months prior to today's date, plus long-term support releases.
MDN supports these browsers, along with Firefox for iOS and all currently active Firefox ESR versions:
- Apple Safari (iOS, macOS) — released within the last 2½ years
- Google Chrome (Android, Desktop) — released within the last 2½ years
- Microsoft Edge (Desktop) — released within the last 2½ years
- Mozilla Firefox (Android, Desktop, iOS) — released within the last 2½ years
- Mozilla Firefox ESR — currently supported by Mozilla
In this context,supported means that any issues with rendering or functionality are considered bugs and will be addressed as soon as reasonably possible.
For issues encountered while using unsupported browsers, we decide on a case-by-case assessment of whether the issue will be addressed; however, these issues may have lower priority. Issues with screen readers and other accessibility aids are likely to carry higher levels of importance.
We make our best efforts to design MDN to degrade gracefully; however, there are no guarantees of any level of functionality outside the supported browser set.
Seethe environment variables README.
We need to run some JS as soon as possible at page load, to avoid layout shifts and flashes.We place this JS inentry.inline.js, and it's inlined on page load.Rspack also generates the necessary CSP hash when doing a prod build withnpm run build.
If this code is component-specific, it can beimported with?source&csp=true and used to set the value ofstatic inlineScript in a Server Component.Remember to add an additional entry to the CSP hashes in yari when doing so.
We support a range of non-standard imports in our JavaScript. This includes:
Imports the raw source of the file as a string.
importtextfrom"./some-file.txt?source";
Logs a CSP hash for the source of the file during the production build.Most commonly used alongside?source to import the source of a file for inlining in a component, which needs to be allowlisted in our CSP:
importinlineScriptfrom"./inline.js?source&csp=true";
We have a basic sandbox for testing and styling components in isolation athttp://localhost:3000/sandbox
To add a component to the sandbox, add asandbox.js file to the component, which exports a class named likeMyComponentSandbox which extends theSandboxComponent exported fromcomponents/sandbox/class.js.
- Components should live in the
components/folder, with reserved names which cause certain behavior, explained further below:component-name/global.css- (reserved): automatically added to global styleselement.js- (reserved): custom element, automatically imported client side, always imported server sideelement.css- (recommended): styles for custom element's shadow domserver.js- (reserved): server component, will automatically load the adjacentserver.cssfile when usedserver.css- (reserved): automatically added to page styles when its server component is used in that page
global.css: components which have CSS which should be loaded onall pages should expose that through aglobal.cssfile:- This should be used sparingly, use it for things needed in almost all components, like colors, fonts, etc.
- Or, when creating a custom element, use it to set the "browser default" styles on that custom element: usually as simple as just
mdn-component-name { display: block; }or similar
element.js: custom elements should be defined incomponents/component-name/element.js- The class should be exported, and named
MDNComponentName- Acronyms should be kept all caps, to match the naming of
HTMLElementclass names, and added toACRONYMSinbuild/plugins/generate-element-map.jsto allow the correct types to be generated
- Acronyms should be kept all caps, to match the naming of
- The element should be registered with a name of
mdn-component-name - If all this is done:
- The element will be automatically loaded client side if it's present in the DOM at page load
- Elements inserted client side (i.e. in a hook, or another custom element) won't be automatically loaded, and the hook should handle loading them: probably with an async
import()
- Elements inserted client side (i.e. in a hook, or another custom element) won't be automatically loaded, and the hook should handle loading them: probably with an async
- The element will be automatically loaded server side for SSR
- The element will automatically be added to
types/element-map.d.tsto provide proper types in e.g.querySelector("mdn-component-name")
- The element will be automatically loaded client side if it's present in the DOM at page load
- The class should be exported, and named
server.js: server components should be defined incomponents/component-name/server.js- The class should extend
ServerComponentfromcomponents/server/index.js, and be namedComponentName
- The class should extend
server.css: server component styles should be placed incomponents/component-name/server.css- These will be automatically loaded server side when the adjacent
ServerComponentis used- Therefore, these styles should be scoped to the component, usually with a wrapping class
- These will be automatically loaded server side when the adjacent
- We useTypeScript in JSDoc annotations for typing, so we can write and directly execute JavaScript (with no transpilation step)
- We occasionally use TypeScript files directly for writing types/interface which are too complex to easily write in JSDoc
- Eventually we'll have a fully typed codebase, with no errors: while we're in active development we can ignore errors in the interest of development speed/pragmatism:
- If we do so, we should use
// @ts-expect-errorso we get an error when we fix the error and don't leave unnecessary// @ts-ignorecomments lying around. While we're in active development these can lack a comment, but eventually we'll require an explanatory comment on each.
- If we do so, we should use
If our server side rendered custom elements are different to the initial state of our custom elements when rendered client side, Lit will error out during hydration, stopping the execution of our client side JS.
To avoid this, don't compute things that are server/client dependent inconnectedCallback (or run functions which do this). Instead you must run these infirstUpdated (despite the warning lit will raise in development about the element scheduling an update after an update completed).
This issue is tracked upstream:lit/lit#1434
About
MDN's frontend since late 2025, built with Web Components, Lit, and SSR for a fast, clean documentation experience. Fred = /fr(ont)e(n)d/.
Topics
Resources
License
Code of conduct
Contributing
Security policy
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Uh oh!
There was an error while loading.Please reload this page.