From React and Next.js
From React and Next.js in the Tailwind CSS with ShadowJS guide.
| React / Next.js | ShadowJS |
|---|---|
className="..." |
class="...". On elements className is also accepted and written to class, so a pasted JSX block works; component props are passed as you name them |
className={clsx("a", { b: on })} |
class={["a", { b: on() }]} with no import; class takes strings, arrays and objects |
className={cn(buttonVariants({ variant }), className)} |
class={cn(button({ variant, class: props.class }))}: see Variants |
htmlFor, tabIndex, readOnly |
The same names work on elements (the compiler lower-cases them to the HTML attribute) |
style={{ ... }} |
Same; keys are camelCase or --custom-property |
PostCSS: postcss.config.js plus tailwind.config.js |
@tailwindcss/vite in vite.config.ts; the template has neither file |
app/globals.css with @tailwind directives |
One CSS file imported from main.tsx; the template's contains @import "tailwindcss"; |
@apply in CSS |
CSS is untouched by ShadowJS; see Tailwind documentation |
| Conditional classes recomputed on every render | The expression inside class={...} is its own binding: only that attribute updates when its signals change |
data-[state=open]:... on Radix parts |
The same data-state, data-disabled, data-orientation, data-side attributes come from @shadow-js/primitives; see shadcn/ui and Radix |
dark: with a dark class on <html> |
Same; toggle the class in an effect, as above |
| CSS-in-JS runtimes (styled-components, emotion) | No ShadowJS integration exists; use Tailwind or plain CSS |
src/migrated.tsxtsx
// React: <button className={clsx("px-4 py-2 rounded", pending ? "bg-gray-400" : "bg-blue-600 text-white hover:bg-blue-700")}>
import { useStore } from "@shadow-js/core";
export function Migrated() {
const [pending] = useStore(false);
return (
<button type="button" class={["px-4 py-2 rounded", pending() ? "bg-gray-400" : "bg-blue-600 text-white hover:bg-blue-700"]}>
Pay
</button>
);
}