Alfan Jauhari
EST2026

Architecting

Tomorrow's

Digital

Landscape

Loading Experience...
AJ.
TypeScriptTypeScriptReact

Sandpack Templates

This snippet gives you more control over Sandpack, letting you compose editors, previews, tests, and files however you want without being boxed into the default setup.

sandpack-utils.ts

import type {
  CodeEditorProps,
  PreviewProps,
  SandpackProviderProps,
  SandpackTests,
} from "@codesandbox/sandpack-react";
import {
  Children,
  type ComponentProps,
  isValidElement,
  type ReactNode,
} from "react";

export interface SandpackProps extends SandpackProviderProps {
  editorProps?: CodeEditorProps;
  previewProps?: PreviewProps;
  testProps?: ComponentProps<typeof SandpackTests>;
}

export const COMMON_FILES = {
  "tsconfig.json": {
    code: JSON.stringify({
      include: ["./**/*"],
      compilerOptions: {
        strict: true,
        esModuleInterop: true,
        lib: ["dom", "es2015"],
        jsx: "react-jsx",
      },
    }),
    hidden: true,
    readOnly: true,
  },
};

export function getFiles(children: ReactNode) {
  const fileEntries = Children.toArray(children)
    .map((child) => {
      if (!isValidElement<{ name: string; children: string }>(child)) {
        return null;
      }

      return [child.props.name, child.props.children];
    })
    .filter((child): child is [string, string] => {
      return child !== null;
    });

  return Object.fromEntries(fileEntries);
}

export const TestTemplateSandpack: (
  props: SandpackProps,
) => SandpackProviderProps = ({ files: _files, children, ...props }) => {
  const files = getFiles(children);

  return {
    files: {
      "package.json": {
        code: JSON.stringify({
          dependencies: {},
          devDependencies: { typescript: "^4.0.0" },
          main: Object.keys(files)[0],
        }),
        hidden: true,
        readOnly: true,
      },
      ...COMMON_FILES,
      ...files,
    },
    customSetup: {
      environment: "parcel",
    },
    ...props,
  };
};

export const ReactTemplateSandpack: (
  props: SandpackProps,
) => SandpackProviderProps = ({ files: _files, children, ...props }) => {
  const files = getFiles(children);

  return {
    files: {
      "package.json": {
        code: JSON.stringify({
          dependencies: {
            react: "^19.0.0",
            "react-dom": "^19.0.0",
            "react-scripts": "^4.0.0",
          },
          devDependencies: {
            "@types/react": "^19.0.0",
            "@types/react-dom": "^19.0.0",
            typescript: "^4.0.0",
          },
          main: "/index.tsx",
        }),
        hidden: true,
        readOnly: true,
      },
      ...COMMON_FILES,
      "/index.tsx": {
        code: `import React, { StrictMode } from "react";
import { createRoot } from "react-dom/client";

import App from "./App";

const root = createRoot(document.getElementById("root"));
root.render(
  <StrictMode>
    <App />
  </StrictMode>
);`,
        hidden: true,
        readOnly: true,
      },
      "/public/index.html": {
        code: `<!DOCTYPE html>
  <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Document</title>
    </head>
    <body>
      <div id="root"></div>
    </body>
  </html>`,
        hidden: true,
        readOnly: true,
      },
      ...files,
    },
    customSetup: {
      environment: "create-react-app-typescript",
    },
    ...props,
  };
};

export type GetSandpackProps = Omit<SandpackProps, "template"> & {
  template: "react" | "test";
};

export function getSandpackProps({ template, ...props }: GetSandpackProps) {
  switch (template) {
    case "test":
      return TestTemplateSandpack(props);
    default:
      return ReactTemplateSandpack(props);
  }
}

sandpack.tsx

import { getSandpackProps } from './sandpack-utils'

<SandpackProvider
  {...getSandpackProps({
    template: 'react' | 'test',
    // customize based on your needs
    style: {
      "--sp-layout-height": "420px",
    } as CSSProperties,
    options: {
      classes: {
        "sp-tab-container": "outline-none!",
        "sp-code-editor": "[&_.cm-gutterElement]:text-xs",
      },
    },
    ...props,
  })}
>
  <SandpackLayout className="border-none! rounded-none!">
    <SandpackCodeEditor
      showLineNumbers
      showInlineErrors
      wrapContent
      {...editorProps}
    />
    {template === "test" ? (
      <SandpackTests {...testProps} />
    ) : (
      <SandpackPreview {...previewProps} />
    )}
  </SandpackLayout>
</SandpackProvider>