diff --git a/src/components/InteractiveSandbox.tsx b/src/components/InteractiveSandbox.tsx
index b5c2cdabe..aedc5189d 100644
--- a/src/components/InteractiveSandbox.tsx
+++ b/src/components/InteractiveSandbox.tsx
@@ -1,4 +1,5 @@
import React from 'react'
+import { stackBlitzIframeProps } from '~/utils/stackblitz-embed'
interface InteractiveSandboxProps {
isActive: boolean
@@ -17,6 +18,8 @@ export function InteractiveSandbox({
libraryName,
embedEditor,
}: InteractiveSandboxProps) {
+ const isStackBlitz = embedEditor === 'stackblitz'
+
return (
diff --git a/src/components/StackBlitzEmbed.tsx b/src/components/StackBlitzEmbed.tsx
index 0cb606864..11e54fdbc 100644
--- a/src/components/StackBlitzEmbed.tsx
+++ b/src/components/StackBlitzEmbed.tsx
@@ -1,5 +1,6 @@
import * as React from 'react'
import { useIsDark } from '~/hooks/useIsDark'
+import { stackBlitzIframeProps } from '~/utils/stackblitz-embed'
type StackBlitzEmbedProps = {
repo: string
@@ -32,6 +33,7 @@ export function StackBlitzEmbed({
title={title || `${repo}: ${examplePath}`}
key={`${examplePath}-${themeParam}`}
src={src}
+ {...stackBlitzIframeProps}
sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"
className="shadow-lg"
loading="lazy"
diff --git a/src/routes/$libraryId/$version.docs.framework.$framework.examples.$.tsx b/src/routes/$libraryId/$version.docs.framework.$framework.examples.$.tsx
index fb5882417..79594b3c8 100644
--- a/src/routes/$libraryId/$version.docs.framework.$framework.examples.$.tsx
+++ b/src/routes/$libraryId/$version.docs.framework.$framework.examples.$.tsx
@@ -24,6 +24,7 @@ import {
ExampleDeployDialog,
type DeployProvider,
} from '~/components/ExampleDeployDialog'
+import { stackBlitzEmbedHeaders } from '~/utils/stackblitz-embed'
const renderedFileQueryOptions = (
repo: string,
@@ -136,6 +137,7 @@ export const Route = createFileRoute(
}),
}
},
+ headers: () => stackBlitzEmbedHeaders,
staleTime: 1000 * 60 * 5, // 5 minutes
})
diff --git a/src/routes/-library-landing.tsx b/src/routes/-library-landing.tsx
index 145e93917..fdec74e97 100644
--- a/src/routes/-library-landing.tsx
+++ b/src/routes/-library-landing.tsx
@@ -9,6 +9,7 @@ import { getTanstackDocsConfig } from '~/utils/config'
import { fetchLandingCodeExample } from '~/utils/landing-code-example.functions'
import { seo } from '~/utils/seo'
import { ogImageUrl } from '~/utils/og'
+import { stackBlitzEmbedHeaders } from '~/utils/stackblitz-embed'
export type LandingComponentProps = {
landingCodeExampleRsc?: ReactNode
@@ -16,6 +17,10 @@ export type LandingComponentProps = {
type LandingComponent = ComponentType
+type LibraryLandingPageOptions = {
+ hasStackBlitzEmbed?: boolean
+}
+
type StaticLandingRoutePath =
| '/ai/$version/'
| '/cli/$version/'
@@ -108,6 +113,7 @@ export function createLibraryLandingPage(
routePath: TId,
libraryId: LibraryId,
LandingComponent: LandingComponent,
+ options: LibraryLandingPageOptions = {},
) {
const library = getLibrary(libraryId)
const routeApi = getRouteApi(routePath)
@@ -181,6 +187,9 @@ export function createLibraryLandingPage(
noindex: library.visible === false,
}),
}),
+ ...(options.hasStackBlitzEmbed
+ ? { headers: () => stackBlitzEmbedHeaders }
+ : {}),
staticData: {
Title: () => (
diff --git a/src/routes/form.$version.index.tsx b/src/routes/form.$version.index.tsx
index 4c9eeb511..9561ea50d 100644
--- a/src/routes/form.$version.index.tsx
+++ b/src/routes/form.$version.index.tsx
@@ -3,5 +3,7 @@ import FormLanding from '~/components/landing/FormLanding'
import { createLibraryLandingPage } from './-library-landing'
export const Route = createFileRoute('/form/$version/')(
- createLibraryLandingPage('/form/$version/', 'form', FormLanding),
+ createLibraryLandingPage('/form/$version/', 'form', FormLanding, {
+ hasStackBlitzEmbed: true,
+ }),
)
diff --git a/src/routes/query.$version.index.tsx b/src/routes/query.$version.index.tsx
index d15de6706..9dfba0812 100644
--- a/src/routes/query.$version.index.tsx
+++ b/src/routes/query.$version.index.tsx
@@ -3,5 +3,7 @@ import QueryLanding from '~/components/landing/QueryLanding'
import { createLibraryLandingPage } from './-library-landing'
export const Route = createFileRoute('/query/$version/')(
- createLibraryLandingPage('/query/$version/', 'query', QueryLanding),
+ createLibraryLandingPage('/query/$version/', 'query', QueryLanding, {
+ hasStackBlitzEmbed: true,
+ }),
)
diff --git a/src/routes/ranger.$version.index.tsx b/src/routes/ranger.$version.index.tsx
index 17bc06430..d98f0006b 100644
--- a/src/routes/ranger.$version.index.tsx
+++ b/src/routes/ranger.$version.index.tsx
@@ -3,5 +3,7 @@ import RangerLanding from '~/components/landing/RangerLanding'
import { createLibraryLandingPage } from './-library-landing'
export const Route = createFileRoute('/ranger/$version/')(
- createLibraryLandingPage('/ranger/$version/', 'ranger', RangerLanding),
+ createLibraryLandingPage('/ranger/$version/', 'ranger', RangerLanding, {
+ hasStackBlitzEmbed: true,
+ }),
)
diff --git a/src/routes/router.$version.index.tsx b/src/routes/router.$version.index.tsx
index 1a3f4f77f..7ed0c7847 100644
--- a/src/routes/router.$version.index.tsx
+++ b/src/routes/router.$version.index.tsx
@@ -3,5 +3,7 @@ import RouterLanding from '~/components/landing/RouterLanding'
import { createLibraryLandingPage } from './-library-landing'
export const Route = createFileRoute('/router/$version/')(
- createLibraryLandingPage('/router/$version/', 'router', RouterLanding),
+ createLibraryLandingPage('/router/$version/', 'router', RouterLanding, {
+ hasStackBlitzEmbed: true,
+ }),
)
diff --git a/src/routes/table.$version.index.tsx b/src/routes/table.$version.index.tsx
index cc3bd907a..622c268d8 100644
--- a/src/routes/table.$version.index.tsx
+++ b/src/routes/table.$version.index.tsx
@@ -3,5 +3,7 @@ import TableLanding from '~/components/landing/TableLanding'
import { createLibraryLandingPage } from './-library-landing'
export const Route = createFileRoute('/table/$version/')(
- createLibraryLandingPage('/table/$version/', 'table', TableLanding),
+ createLibraryLandingPage('/table/$version/', 'table', TableLanding, {
+ hasStackBlitzEmbed: true,
+ }),
)
diff --git a/src/routes/virtual.$version.index.tsx b/src/routes/virtual.$version.index.tsx
index eb50c1564..6b354b009 100644
--- a/src/routes/virtual.$version.index.tsx
+++ b/src/routes/virtual.$version.index.tsx
@@ -3,5 +3,7 @@ import VirtualLanding from '~/components/landing/VirtualLanding'
import { createLibraryLandingPage } from './-library-landing'
export const Route = createFileRoute('/virtual/$version/')(
- createLibraryLandingPage('/virtual/$version/', 'virtual', VirtualLanding),
+ createLibraryLandingPage('/virtual/$version/', 'virtual', VirtualLanding, {
+ hasStackBlitzEmbed: true,
+ }),
)
diff --git a/src/utils/stackblitz-embed.ts b/src/utils/stackblitz-embed.ts
new file mode 100644
index 000000000..3454fc7a8
--- /dev/null
+++ b/src/utils/stackblitz-embed.ts
@@ -0,0 +1,13 @@
+import type { IframeHTMLAttributes } from 'react'
+
+export const stackBlitzEmbedHeaders = {
+ 'Cross-Origin-Opener-Policy': 'same-origin',
+ 'Cross-Origin-Embedder-Policy': 'credentialless',
+} as const
+
+export const stackBlitzIframeProps = {
+ allow: 'cross-origin-isolated',
+ credentialless: '',
+} as IframeHTMLAttributes & {
+ credentialless: string
+}