Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
53d912c
Add prop compression pattern
dav-is Mar 28, 2026
272898f
Restructure doc
dav-is Mar 28, 2026
33f5557
Add abstracting note to docs
dav-is Mar 28, 2026
a95a0c9
More docs improvements
dav-is Mar 28, 2026
6420b9a
Add link to base ui case
dav-is Mar 28, 2026
1462865
Update index
dav-is Mar 28, 2026
e7eaffe
Another pass at the doc
dav-is Mar 28, 2026
4b3f598
Add initial implementation
dav-is Mar 30, 2026
cb0f660
Merge branch 'master' into docs-infra/type-prop-compression
dav-is Mar 30, 2026
33e3b40
Preserve frames in unhighlighted code
dav-is Mar 31, 2026
d921704
Also convert types
dav-is Mar 31, 2026
b7bfcd4
Merge branch 'master' into docs-infra/type-prop-compression
dav-is Mar 31, 2026
74795d2
Add a compression dictionary
dav-is Mar 31, 2026
44cc7d4
Merge branch 'docs-infra/type-prop-compression' of github.com:mui/mui…
dav-is Mar 31, 2026
37a5a0c
Update index and types
dav-is Mar 31, 2026
2f8424c
Add more items to dictionary
dav-is Mar 31, 2026
49e5778
Rename hastGzip to hastCompressed
dav-is Mar 31, 2026
1355301
Avoid recompressing
dav-is Mar 31, 2026
55aee58
Improve impact section
dav-is Mar 31, 2026
41e6ec4
Add CodeComponentsContext
dav-is Mar 31, 2026
af0d1ef
Fix frame detection
dav-is Mar 31, 2026
6ee1ea8
Prettier
dav-is Mar 31, 2026
9e50c1b
Remove data-frame-start-line, data-frame-end-line, and data-frame attrs
dav-is Mar 31, 2026
029cb12
Fix lint
dav-is Mar 31, 2026
f122ac0
Remove `shortTypeText` and `typeText` from highlighted typed
dav-is Mar 31, 2026
7589772
Add some context about page weight
dav-is Mar 31, 2026
55a74b3
Strip data-lined property
dav-is Mar 31, 2026
b656016
Improve dictionary
dav-is Apr 1, 2026
aa6a058
Update docs
dav-is Apr 1, 2026
b4ae3aa
Add text content into compression pipeline
dav-is Apr 3, 2026
af630e7
First step in restructuring fallback compression
dav-is Apr 3, 2026
7c36c39
Merge branch 'master' into docs-infra/type-prop-compression
dav-is Apr 3, 2026
1772b29
Merge branch 'docs-infra/type-prop-compression' of github.com:mui/mui…
dav-is Apr 3, 2026
36c6abc
Add missing files
dav-is Apr 3, 2026
0b4c7ab
Fix typesToJsx
dav-is Apr 3, 2026
fc5ed60
Update Base UI benchmark
dav-is Apr 3, 2026
3a8e261
Improve document
dav-is Apr 3, 2026
a30939d
Update index and prettier
dav-is Apr 3, 2026
a0165bf
Add intersection observer
dav-is Apr 3, 2026
1890ebb
Rename to TypeCode component
dav-is Apr 3, 2026
3b0e173
Update pattern document
dav-is Apr 3, 2026
de2080c
Improve doc
dav-is Apr 3, 2026
801772e
Remove large snippet result
dav-is Apr 3, 2026
007dd0e
Update formatting
dav-is Apr 3, 2026
1115850
Improve visibility detection
dav-is Apr 3, 2026
920b360
Code review
dav-is Apr 3, 2026
08eb9a1
Code review
dav-is Apr 3, 2026
57cb31c
Code review
dav-is Apr 3, 2026
381e9c9
Update types.md
dav-is Apr 3, 2026
9a36446
Code review
dav-is Apr 3, 2026
1f8d618
Code review
dav-is Apr 3, 2026
8f8b5c2
Add more nuance to results
dav-is Apr 6, 2026
544471a
Merge branch 'master' into docs-infra/type-prop-compression
dav-is Apr 7, 2026
92a3e06
Merge branch 'master' into docs-infra/type-prop-compression
dav-is Apr 7, 2026
07f7f56
Merge branch 'docs-infra/type-prop-compression' into docs-infra/impro…
dav-is Apr 9, 2026
c26abe6
Add a more realistic benchmark
dav-is Apr 9, 2026
3197b1d
Prettier
dav-is Apr 9, 2026
d7d92f4
More edits to doc
dav-is Apr 9, 2026
c4666d0
Prettier
dav-is Apr 9, 2026
6460004
Clarify performance more
dav-is Apr 9, 2026
8e544dd
update index
dav-is Apr 9, 2026
52f5daf
Merge branch 'master' into docs-infra/type-prop-compression
dav-is Apr 9, 2026
8692cc5
reduce number of lines in example
dav-is Apr 9, 2026
317fa6c
Doc review
dav-is Apr 9, 2026
33e59a3
And another caveat
dav-is Apr 9, 2026
0ad8313
prettier
dav-is Apr 9, 2026
b213647
Update link
dav-is Apr 9, 2026
8d53bb1
Fix broken link
dav-is Apr 9, 2026
36c730a
Merge branch 'master' into docs-infra/type-prop-compression
dav-is Apr 10, 2026
774f4fa
Merge branch 'master' into docs-infra/type-prop-compression
dav-is Apr 13, 2026
e794bd0
Merge branch 'master' into docs-infra/type-prop-compression
dav-is Apr 15, 2026
a74d644
Fix formatting of documentation tip for visibility option
dav-is Apr 16, 2026
47c0c8d
Remove rehype weight note
dav-is Apr 16, 2026
604ed62
Merge branch 'docs-infra/type-prop-compression' into docs-infra/impro…
dav-is Apr 16, 2026
f334b1c
Merge branch 'master' into docs-infra/improve-code-fallback-compression
dav-is Apr 16, 2026
c611725
Merge branch 'master' into docs-infra/improve-code-fallback-compression
dav-is Apr 23, 2026
0924912
Merge branch 'master' into docs-infra/improve-code-fallback-compression
dav-is Apr 28, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ import styles from './CodeContent.module.css';

import '../../../../../docs-infra/components/code-highlighter/demos/syntax.css';

export function CodeContentLoading(props: ContentLoadingProps<{}>) {
export function CodeContentLoading(_props: ContentLoadingProps<{}>) {
return (
<div>
{/* @focus-start */}
<div className={styles.code}>
<pre className={styles.codeBlock}>{props.source}</pre>
<pre className={styles.codeBlock} />
</div>
{/* @focus-end */}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import * as React from 'react';
import type { ContentLoadingProps } from '@mui/internal-docs-infra/CodeHighlighter/types';
import { useCodeFallback } from '@mui/internal-docs-infra/CodeHighlighter';
import { hastToJsx } from '@mui/internal-docs-infra/pipeline/hastUtils';
import { Tabs } from '@/components/Tabs';
import styles from '../DemoContent.module.css';
import loadingStyles from './DemoContentLoading.module.css';
Expand All @@ -10,6 +12,7 @@ import '../syntax.css';

export function DemoContentLoading(props: ContentLoadingProps<object>) {
// @focus-start
const { source, extraSource } = useCodeFallback(props);
const tabs = React.useMemo(
() =>
props.fileNames?.map((name) => ({
Expand Down Expand Up @@ -47,11 +50,11 @@ export function DemoContentLoading(props: ContentLoadingProps<object>) {
</div>
</div>
<div className={styles.code}>
<pre className={styles.codeBlock}>{props.source}</pre>
<pre className={styles.codeBlock}>{source ? hastToJsx(source) : null}</pre>
</div>
<div className={loadingStyles.extraFiles}>
{Object.keys(props.extraSource || {}).map((slug) => (
<pre key={slug}>{props.extraSource?.[slug]}</pre>
{Object.keys(extraSource || {}).map((slug) => (
<pre key={slug}>{extraSource?.[slug] ? hastToJsx(extraSource[slug]) : null}</pre>
))}
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import * as React from 'react';
import type { ContentLoadingProps } from '@mui/internal-docs-infra/CodeHighlighter/types';
import { useCodeFallback } from '@mui/internal-docs-infra/CodeHighlighter';
import { hastToJsx } from '@mui/internal-docs-infra/pipeline/hastUtils';
import { Tabs } from '@/components/Tabs';
import { Select } from '@/components/Select';
import styles from '../DemoContent.module.css';
Expand All @@ -15,6 +17,7 @@ const variantNames: Record<string, string | undefined> = {

export function DemoContentLoading(props: ContentLoadingProps<object>) {
// @focus-start
const { source, extraSource, extraVariants } = useCodeFallback(props);
const tabs = React.useMemo(
() =>
props.fileNames?.map((name) => ({
Expand All @@ -39,7 +42,7 @@ export function DemoContentLoading(props: ContentLoadingProps<object>) {

return (
<div>
{Object.keys(props.extraSource || {}).map((slug) => (
{Object.keys(extraSource || {}).map((slug) => (
<span key={slug} id={slug} className={styles.fileRefs} />
))}
<div className={styles.container}>
Expand All @@ -58,28 +61,31 @@ export function DemoContentLoading(props: ContentLoadingProps<object>) {
</div>
)}
<div className={styles.headerActions}>
{Object.keys(props.extraVariants || {}).length >= 1 && (
{Object.keys(extraVariants || {}).length >= 1 && (
<Select items={variants} value={variants[0]?.value} disabled={true} />
)}
</div>
</div>
</div>
<div className={styles.code}>
<pre className={styles.codeBlock}>{props.source}</pre>
<pre className={styles.codeBlock}>{source ? hastToJsx(source) : null}</pre>
</div>
<div className={loadingStyles.extraFiles}>
{Object.keys(props.extraSource || {}).map((slug) => (
<pre key={slug}>{props.extraSource?.[slug]}</pre>
{Object.keys(extraSource || {}).map((slug) => (
<pre key={slug}>{extraSource?.[slug] ? hastToJsx(extraSource[slug]) : null}</pre>
))}
</div>
<div className={loadingStyles.extraVariants}>
{Object.keys(props.extraVariants || {}).map((slug) => (
{Object.keys(extraVariants || {}).map((slug) => (
<div key={slug} className={loadingStyles.extraVariant}>
<span>{slug}</span>
<pre>
{Object.keys(props.extraVariants?.[slug].extraSource || {}).map((key) => (
{Object.keys(extraVariants?.[slug].extraSource || {}).map((key) => (
<div key={key}>
<strong>{key}:</strong> {props.extraVariants?.[slug]?.extraSource?.[key]}
<strong>{key}:</strong>{' '}
{extraVariants?.[slug]?.extraSource?.[key]
? hastToJsx(extraVariants[slug].extraSource![key])
: null}
</div>
))}
</pre>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@

import * as React from 'react';
import type { ContentLoadingProps } from '@mui/internal-docs-infra/CodeHighlighter/types';
import { useCodeFallback } from '@mui/internal-docs-infra/CodeHighlighter';
import { hastToJsx } from '@mui/internal-docs-infra/pipeline/hastUtils';
import { Tabs } from '@/components/Tabs';
import styles from '../DemoContent.module.css';

import '../syntax.css';

export function DemoContentLoading(props: ContentLoadingProps<object>) {
// @focus-start
const { source } = useCodeFallback(props);
const tabs = React.useMemo(
() =>
props.fileNames?.map((name) => ({
Expand Down Expand Up @@ -46,7 +49,7 @@ export function DemoContentLoading(props: ContentLoadingProps<object>) {
</div>
</div>
<div className={styles.code}>
<pre className={styles.codeBlock}>{props.source}</pre>
<pre className={styles.codeBlock}>{source ? hastToJsx(source) : null}</pre>
</div>
</div>
</div>
Expand Down
113 changes: 107 additions & 6 deletions docs/app/docs-infra/components/code-highlighter/types.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,15 +145,51 @@ type ReturnValue = HastRoot | Promise<HastRoot>;
type ReturnValue = Promise<Record<string, { source: string; fileName?: string }> | undefined>;
```

### useCodeFallback

Hook for `ContentLoading` components to hoist fallback data
to `CodeHighlighterClient` for text-dictionary derivation.

On the server-rendered path, Code is stripped of `fallback` entries
and the data arrives on ContentLoading as `source`/`extraSource` props
in compact `FallbackNode[]` format. This hook converts them back to
`HastRoot` for rendering and hoists the compact form for dictionaries.

On the client-loaded path, `useInitialData` already hoists directly,
so this hook simply passes props through.

**useCodeFallback Parameters:**

| Parameter | Type | Default | Description |
| :-------- | :--------------------- | :------ | :---------- |
| props | `UseCodeFallbackProps` | - | - |

**useCodeFallback Return Value:**

```tsx
type ReturnValue = UseCodeFallbackResult;
```

## Additional Types

### UseCodeFallbackResult

```typescript
type UseCodeFallbackResult = {
source?: HastRoot;
fileNames?: string[];
extraSource?: Record<string, HastRoot>;
extraVariants?: Record<string, UseCodeFallbackVariantResult>;
};
```

### BaseContentLoadingProps

```typescript
type BaseContentLoadingProps = {
fileNames?: string[];
source?: React.ReactNode;
extraSource?: { [fileName: string]: React.ReactNode };
source?: FallbackNode[];
extraSource?: Record<string, FallbackNode[]>;
/** Display name for the code example, used for identification and titles */
name?: string;
/** URL-friendly identifier for deep linking and navigation */
Expand Down Expand Up @@ -541,6 +577,7 @@ type ContentLoadingProps<T extends {}> = ContentLoadingVariant &
component: React.ReactNode;
components?: Record<string, React.ReactNode>;
initialFilename?: string;
initialVariant?: string;
};
```

Expand All @@ -549,8 +586,8 @@ type ContentLoadingProps<T extends {}> = ContentLoadingVariant &
```typescript
type ContentLoadingVariant = {
fileNames?: string[];
source?: React.ReactNode;
extraSource?: { [fileName: string]: React.ReactNode };
source?: FallbackNode[];
extraSource?: Record<string, FallbackNode[]>;
};
```

Expand Down Expand Up @@ -607,6 +644,16 @@ type ExternalImportItem = {
type Externals = { [key: string]: ExternalImportItem[] };
```

### Fallbacks

Record of `fileName → compact fallback` extracted from variants.
Used as the DEFLATE dictionary for `hastCompressed` decompression and
as the visual fallback before full highlighting loads.

```typescript
type Fallbacks = { [key: string]: FallbackNode[] };
```

### HastRoot

```typescript
Expand Down Expand Up @@ -640,6 +687,21 @@ type LoadFallbackCodeOptions = {
* @default 'hast'
*/
output?: 'hast' | 'hastJson' | 'hastCompressed';
/**
* When `true` and `output` is `'hastCompressed'`, the text content of
* the fallback HAST is used as a DEFLATE dictionary during compression,
* producing smaller payloads. The resulting `fallbackHast` is included
* on the variant so it can travel via context to the client and be used
* to reconstruct the same dictionary for decompression.
*
* Set this to `true` only when a `ContentLoading` component is present,
* since the compressed data can only be decompressed when the fallbackHast
* is available in the `CodeHighlighterFallbackContext`.
*
* When `false` (the default), only the static shared dictionary is used.
* @default false
*/
compressWithFallbackDictionary?: boolean;
/** Function to load code metadata from a URL */
loadCodeMeta?: LoadCodeMeta;
/** Function to load specific variant metadata */
Expand Down Expand Up @@ -682,6 +744,21 @@ type LoadFileOptions = {
* @default 'hast'
*/
output?: 'hast' | 'hastJson' | 'hastCompressed';
/**
* When `true` and `output` is `'hastCompressed'`, the text content of
* the fallback HAST is used as a DEFLATE dictionary during compression,
* producing smaller payloads. The resulting `fallbackHast` is included
* on the variant so it can travel via context to the client and be used
* to reconstruct the same dictionary for decompression.
*
* Set this to `true` only when a `ContentLoading` component is present,
* since the compressed data can only be decompressed when the fallbackHast
* is available in the `CodeHighlighterFallbackContext`.
*
* When `false` (the default), only the static shared dictionary is used.
* @default false
*/
compressWithFallbackDictionary?: boolean;
};
```

Expand All @@ -706,6 +783,21 @@ type LoadVariantOptions = {
* @default 'hast'
*/
output?: 'hast' | 'hastJson' | 'hastCompressed';
/**
* When `true` and `output` is `'hastCompressed'`, the text content of
* the fallback HAST is used as a DEFLATE dictionary during compression,
* producing smaller payloads. The resulting `fallbackHast` is included
* on the variant so it can travel via context to the client and be used
* to reconstruct the same dictionary for decompression.
*
* Set this to `true` only when a `ContentLoading` component is present,
* since the compressed data can only be decompressed when the fallbackHast
* is available in the `CodeHighlighterFallbackContext`.
*
* When `false` (the default), only the static shared dictionary is used.
* @default false
*/
compressWithFallbackDictionary?: boolean;
/** Promise resolving to a source parser for syntax highlighting */
sourceParser?: Promise<ParseSource>;
/** Function to load raw source code and dependencies */
Expand Down Expand Up @@ -771,6 +863,14 @@ type VariantCode = {
url?: string;
/** Main source content for this variant */
source?: VariantSource;
/**
* Compact fallback (highlighting spans removed) for the main source.
* Converted from HAST via `hastToFallback` for smaller RSC payloads.
* Used as the visual fallback before full highlighting loads, and its text
* content (via `fallbackToText`) serves as the DEFLATE dictionary for
* decompressing `hastCompressed` payloads.
*/
fallback?: FallbackNode[];
/** Additional files associated with this variant */
extraFiles?: VariantExtraFiles;
/** Prefix for metadata keys, e.g. /src */
Expand Down Expand Up @@ -803,6 +903,7 @@ type VariantExtraFiles = {
| string
| {
source?: VariantSource;
fallback?: FallbackNode[];
language?: string;
transforms?: Transforms;
skipTransforms?: boolean;
Expand All @@ -821,5 +922,5 @@ type VariantSource = string | HastRoot | { hastJson: string } | { hastCompressed

## Export Groups

- `CodeHighlighter`
- `CodeHighlighterTypes`: `Components`, `Transforms`, `ExternalImportItem`, `Externals`, `HastRoot`, `VariantSource`, `VariantExtraFiles`, `VariantCode`, `Code`, `ControlledVariantExtraFiles`, `ControlledVariantCode`, `ControlledCode`, `ContentProps`, `ContentLoadingVariant`, `BaseContentLoadingProps`, `ContentLoadingProps`, `LoadCodeMeta`, `LoadVariantMeta`, `LoadSource`, `TransformSource`, `ParseSource`, `SourceTransformer`, `SourceTransformers`, `SourceComments`, `SourceEnhancer`, `SourceEnhancers`, `LoadFileOptions`, `LoadVariantOptions`, `LoadFallbackCodeOptions`, `CodeIdentityProps`, `CodeContentProps`, `CodeLoadingProps`, `CodeFunctionProps`, `CodeRenderingProps`, `CodeClientRenderingProps`, `CodeHighlighterBaseProps`, `CodeHighlighterClientProps`, `CodeHighlighterProps`
- `CodeHighlighter`: `useCodeFallback`, `UseCodeFallbackResult`, `CodeHighlighter`
- `CodeHighlighterTypes`: `Components`, `Transforms`, `ExternalImportItem`, `Externals`, `HastRoot`, `VariantSource`, `VariantExtraFiles`, `VariantCode`, `Code`, `ControlledVariantExtraFiles`, `ControlledVariantCode`, `ControlledCode`, `ContentProps`, `Fallbacks`, `ContentLoadingVariant`, `BaseContentLoadingProps`, `ContentLoadingProps`, `LoadCodeMeta`, `LoadVariantMeta`, `LoadSource`, `TransformSource`, `ParseSource`, `SourceTransformer`, `SourceTransformers`, `SourceComments`, `SourceEnhancer`, `SourceEnhancers`, `LoadFileOptions`, `LoadVariantOptions`, `LoadFallbackCodeOptions`, `CodeIdentityProps`, `CodeContentProps`, `CodeLoadingProps`, `CodeFunctionProps`, `CodeRenderingProps`, `CodeClientRenderingProps`, `CodeHighlighterBaseProps`, `CodeHighlighterClientProps`, `CodeHighlighterProps`
3 changes: 3 additions & 0 deletions docs/app/docs-infra/components/page.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ It supports both static code blocks and interactive demos with component preview
- Parameters: root, comments, fileName
- TransformSource
- Parameters: source, fileName
- useCodeFallback
- Parameters: props
- Types: UseCodeFallbackResult

</details>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@

import * as React from 'react';
import type { ContentLoadingProps } from '@mui/internal-docs-infra/CodeHighlighter/types';
import { useCodeFallback } from '@mui/internal-docs-infra/CodeHighlighter';
import { hastToJsx } from '@mui/internal-docs-infra/pipeline/hastUtils';
import { Tabs } from '@/components/Tabs';
import styles from '../../app/docs-infra/components/code-highlighter/demos/DemoContent.module.css';

import '../../app/docs-infra/components/code-highlighter/demos/syntax.css';

export function DemoPerformanceContentLoading(props: ContentLoadingProps<object>) {
const { source } = useCodeFallback(props);
const tabs = React.useMemo(
() =>
props.fileNames?.map((name) => ({
Expand Down Expand Up @@ -45,7 +48,7 @@ export function DemoPerformanceContentLoading(props: ContentLoadingProps<object>
</div>
</div>
<div className={styles.code}>
<pre className={styles.codeBlock}>{props.source}</pre>
<pre className={styles.codeBlock}>{source ? hastToJsx(source) : null}</pre>
</div>
</div>
</div>
Expand Down
Loading
Loading