Get StartedComponentsStylingThemingMath & Science
MCP

Astro

npm create astro@latest my-site
cd my-site
npx astro add react
npm i @indoku/ui @emotion/react

Config

Render on the server and make sure React and Emotion are not duplicated:

// astro.config.mjs
import react from "@astrojs/react"
import node from "@astrojs/node"
import { defineConfig } from "astro/config"

export default defineConfig({
  output: "server",
  adapter: node({ mode: "standalone" }),
  integrations: [react()],
  vite: {
    resolve: { dedupe: ["react", "react-dom", "@emotion/react"] },
    ssr: { noExternal: ["@indoku/ui"] },
  },
})

No flash of the wrong theme

Inject the color mode script in <head> so the page paints in the right mode before React hydrates:

---
import { colorModeScript } from "@indoku/ui"
---
<html lang="en">
  <head>
    <script is:inline set:html={colorModeScript} />
  </head>
  <body><slot /></body>
</html>

Islands

Put a Provider inside each island:

// src/components/Counter.tsx
import { Button, Provider } from "@indoku/ui"
import { useState } from "react"

export default function Counter() {
  const [n, setN] = useState(0)
  return (
    <Provider>
      <Button onClick={() => setN(n + 1)}>Clicked {n}</Button>
    </Provider>
  )
}
---
import Counter from "../components/Counter"
---
<Counter client:load />

Because pages render on the server, curl and crawlers receive complete HTML, including the island markup.

Astro needs client:* components imported statically in the .astro file, so group related UI in one island instead of dynamic imports.

Created by @indokudev