# React To Solid

> React-to-SolidJS transformation patterns for porting shadcn-style React components, examples, docs snippets, and blocks into Zaidan. Use when converting React TSX, React hooks, Radix/Base UI/shadcn patterns, Next-style code, or React-specific dependencies to idiomatic SolidJS. Use when this capability is needed.

- Skill: `tomevault-io/react-to-solid` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add tomevault-io/react-to-solid`
- Raw SKILL.md: https://api.skillmd.com/api/skills/tomevault-io/react-to-solid/raw
- Safety review: pending (external: skill-scanner PASS, skillspector PASS)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- Author: tomevault-io (https://skillmd.com/u/tomevault-io)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/tomevault-io/react-to-solid

---


# React to SolidJS

Use this skill for the translation itself. Use
`.agents/skills/zaidan-agent/SKILL.md` for the workflow, source URLs, target
paths, registry updates, browser testing, and command choices.

## Load References Only When Needed

- Read `docs/base-ui-mapping.md` for `@base-ui/react-*`, `@radix-ui/*`, Base UI
  data attributes, or Base UI CSS variables.
- Read `docs/kobalte-patterns.md` when typing or composing Kobalte primitive
  parts.
- Read `docs/corvu-patterns.md` when using Corvu primitives.
- Read `docs/third-party-deps.md` when replacing React-specific third-party
  packages.

## Core Mappings

| React | SolidJS |
| --- | --- |
| `className` | `class` |
| `className?: string` | `class?: string` |
| Destructured props | `splitProps(props, [...])` |
| Destructured default props | `mergeProps(defaults, props)` before `splitProps` |
| `{condition && <El />}` | `<Show when={condition}><El /></Show>` |
| `items.map(...)` in JSX | `<For each={items}>{(item) => ...}</For>` |
| `useState` | `createSignal` or `createStore` |
| `useEffect` | `createEffect`, `onMount`, or `onCleanup` |
| `useMemo` | `createMemo` only for reactive derived values |
| `useCallback` | Usually remove |
| `forwardRef` | Usually remove |
| `React.ReactNode` | `JSX.Element` |
| `React.ComponentProps<"div">` | `ComponentProps<"div">` |
| `lucide-react` | `lucide-solid` |
| `next/image` | Native `<img>` unless local code has a wrapper |
| `next/link` | TanStack Router `Link` or native `<a>` based on local usage |

Use `e.currentTarget` for typed form events. Use signal calls such as `value()`;
do not treat signals like React state variables.

## Import Rewrites

```tsx
// Remove React imports:
import * as React from "react";

// Add Solid imports only when used:
import type { ComponentProps, JSX, ValidComponent } from "solid-js";
import { For, Show, createMemo, createSignal, mergeProps, splitProps } from "solid-js";
import type { PolymorphicProps } from "@kobalte/core/polymorphic";
import { cn } from "@/lib/utils";
```

Common path rewrites:

| React source path | Zaidan path |
| --- | --- |
| `@/registry/bases/base/lib/utils` | `@/lib/utils` |
| `@/registry/bases/base/ui/*` | `@/registry/kobalte/ui/*` |
| `@/registry/bases/base/hooks/*` | `@/registry/kobalte/hooks/*` |
| `@/registry/bases/base/blocks/*` | `@/registry/kobalte/blocks/*` |

## Props Pattern

Use `splitProps`; do not destructure props directly when values are used in JSX.

```tsx
import type { ComponentProps } from "solid-js";
import { splitProps } from "solid-js";
import { cn } from "@/lib/utils";

type CardProps = ComponentProps<"div">;

const Card = (props: CardProps) => {
  const [local, others] = splitProps(props, ["class"]);

  return <div data-slot="card" class={cn("z-card", local.class)} {...others} />;
};
```

Use `mergeProps` first when defaults are needed:

```tsx
const mergedProps = mergeProps({ side: "top" } as TooltipProps, props);
const [local, others] = splitProps(mergedProps, ["class", "side"]);
```

Use Solid's `children()` helper when children must be inspected, normalized, or
reused.

## Primitive Pattern

Prefer Kobalte for accessible shadcn-style primitives. Use Corvu when the repo
already uses it for that component family, when Kobalte does not provide the
primitive, or when Corvu matches the source behavior better.

```tsx
import * as ButtonPrimitive from "@kobalte/core/button";
import type { PolymorphicProps } from "@kobalte/core/polymorphic";
import type { ComponentProps, ValidComponent } from "solid-js";
import { splitProps } from "solid-js";
import { cn } from "@/lib/utils";

type ButtonProps<T extends ValidComponent = "button"> = PolymorphicProps<
  T,
  ButtonPrimitive.ButtonRootProps<T>
> &
  Pick<ComponentProps<T>, "class" | "children">;

const Button = <T extends ValidComponent = "button">(props: ButtonProps<T>) => {
  const [local, others] = splitProps(props as ButtonProps, ["class"]);

  return (
    <ButtonPrimitive.Root
      data-slot="button"
      class={cn("z-button", local.class)}
      {...others}
    />
  );
};
```

Keep primitive imports inside wrapper components. In examples, docs, and blocks,
prefer existing Zaidan wrappers when they exist.

## Preservation Rules

- Preserve behavior, accessibility, public API, Tailwind classes, CSS variables,
  and `data-slot` attributes unless the Solid primitive requires an adaptation.
- Match nearby Zaidan files for naming, exports, data attributes, and types.
- Keep imports minimal.
- Prefer `cn()` from `@/lib/utils` for class merging.

---
> Source: [carere/zaidan](https://github.com/carere/zaidan) — distributed by [TomeVault](https://tomevault.io).
<!-- tomevault:4.0:skill_md:2026-07-07 -->

