@ox-content/vite-plugin-solid
Solid integration for Ox Content - embed Solid components in Markdown.
Installation
vp install @ox-content/vite-plugin-solid solid-js vite-plugin-solid
Usage
// vite.config.ts
import { defineConfig } from "vite";
import solid from "vite-plugin-solid";
import { oxContentSolid } from "@ox-content/vite-plugin-solid";
export default defineConfig({
plugins: [
oxContentSolid({
srcDir: "docs",
// Auto-discover components with glob pattern
components: "./src/components/*.tsx",
}),
solid({ extensions: [".md", ".markdown", ".mdx"] }),
],
});
Plugin Order and extensions
Unlike the Vue, React, and Svelte integrations, this plugin has two setup rules
that are not optional. Both follow from the same fact: Solid's JSX is
compile-time only. There is no runtime element factory like React's
createElement or Vue's h to fall back on, so Markdown is emitted as Solid
JSX and vite-plugin-solid is what turns it into DOM or SSR instructions.
oxContentSolid()must come beforesolid()in thepluginsarray. Both plugins areenforce: "pre", so array order decides which one sees the Markdown file first. Ifsolid()runs first, Babel tries to parse raw Markdown as JSX.solid()must be given the Markdown extensions. By default it only looks at.jsxand.tsxfiles, so the generated modules would be handed to the browser as uncompiled JSX.
Both mistakes are checked for you and reported with the fix — see
verifySolidPlugin.
Options
components
- Type:
string | string[] | Record<string, string>
Components to register for use in Markdown. Supports:
Glob Pattern (Recommended)
// Single pattern
components: "./src/components/*.tsx";
// Multiple patterns
components: ["./src/components/*.tsx", "./src/ui/*.tsx"];
Component names are derived from file names in PascalCase:
counter.tsx→Countermy-button.tsx→MyButton
Explicit Map
components: {
Counter: './src/components/Counter.tsx',
Alert: './src/components/Alert.tsx',
}
verifySolidPlugin
- Type:
boolean - Default:
true
Fail fast on the two setup mistakes described above instead of letting them surface as an unrelated syntax error.
The plugin check runs when the config resolves; the extensions check runs the
first time a Markdown module comes out of the pipeline still uncompiled. Both
throw a message naming the fix.
Turn it off when Solid's JSX is compiled by something other than
vite-plugin-solid.
Using Components in Markdown
# My Page
Here's an interactive counter:
<Counter start={5} />
And an alert:
<Alert type="warning">
This is a warning message!
</Alert>
Example Component
// src/components/Counter.tsx
import { createSignal } from "solid-js";
export default function Counter(props: { start?: number }) {
const [count, setCount] = createSignal(props.start ?? 0);
return (
<div class="counter">
<button onClick={() => setCount(count() - 1)}>-</button>
<span>{count()}</span>
<button onClick={() => setCount(count() + 1)}>+</button>
</div>
);
}
Note that props is not destructured. Solid props are a reactive proxy, and
destructuring them reads every value once at setup time, which is what breaks
reactivity in components ported from React.
Virtual Modules
virtual:ox-content-solid/components- Registered components
import components from "virtual:ox-content-solid/components";
There is no virtual:ox-content-solid/runtime counterpart to the Svelte
integration's: Solid mounts through render from solid-js/web, which the
generated modules import directly.
Islands
Markdown that uses a registered component is emitted with island markers and
hydrated through @ox-content/islands, the same runtime the other framework
integrations use. Each island is mounted with render from solid-js/web and
disposed when the Markdown component unmounts.
Markdown without any registered component skips the island runtime entirely and
compiles to a single innerHTML binding.
HMR
Components are hot-reloaded when modified. Markdown modules that use a changed component are invalidated alongside it.
Rust and N-API Codegen
The Rust renderer can also emit Solid code directly from rendered Markdown HTML, without the Vite pipeline:
import { renderFrameworkComponentCode } from "@ox-content/napi";
renderFrameworkComponentCode("<p>Hello</p>", "solid", [], "component");
That path targets solid-js/h, Solid's hyperscript entry point, because it has
to produce code that runs without the JSX compiler. The Vite plugin emits JSX
instead, which compiles to faster, finer-grained output.