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.mdfor@base-ui/react-*,@radix-ui/*, Base UI data attributes, or Base UI CSS variables. - Read
docs/kobalte-patterns.mdwhen typing or composing Kobalte primitive parts. - Read
docs/corvu-patterns.mdwhen using Corvu primitives. - Read
docs/third-party-deps.mdwhen 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
// 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.
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:
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.
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-slotattributes 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/utilsfor class merging.
Source: carere/zaidan — distributed by TomeVault.