React
npm install @aejkatappaja/phantom-uipnpm add @aejkatappaja/phantom-uiyarn add @aejkatappaja/phantom-uibun add @aejkatappaja/phantom-uiRun npx @aejkatappaja/phantom-ui init once to generate a phantom-ui.d.ts file for JSX types (or create it manually, see TypeScript below).
import { useState, useEffect } from "react";import "@aejkatappaja/phantom-ui";
function UserCard() { const [user, setUser] = useState(null);
useEffect(() => { fetchUser().then(setUser); }, []);
return ( <phantom-ui loading={!user}> <div className="card"> <img src={user?.avatar ?? "/placeholder.png"} className="avatar" /> <h3>{user?.name ?? "Placeholder Name"}</h3> <p>{user?.bio ?? "A short bio goes here for measurement."}</p> </div> </phantom-ui> );}Boolean attributes
Section titled “Boolean attributes”phantom-ui treats loading="false" as falsy, so you can pass booleans directly:
<phantom-ui loading={isLoading}>This works the same in React 18 and React 19. React 18 sets loading as a string attribute ("true" / "false"); the component resolves it to a boolean and clears the stale attribute when it becomes falsy, so content is revealed correctly when loading ends.
TypeScript
Section titled “TypeScript”If you prefer not to run init, create src/phantom-ui.d.ts manually:
import type { PhantomUiAttributes } from "@aejkatappaja/phantom-ui";
declare module "react/jsx-runtime" { export namespace JSX { interface IntrinsicElements { "phantom-ui": PhantomUiAttributes; } }}Or run:
npx @aejkatappaja/phantom-ui initpnpm dlx @aejkatappaja/phantom-ui inityarn dlx @aejkatappaja/phantom-ui initbunx @aejkatappaja/phantom-ui init