How to Integrate Extracted Content with shadcn/ui Component Primitives

You integrate extracted content with shadcn/ui component primitives by generating a React icons module from cloned SVGs, extending cva variant definitions with extracted design-token classes, and merging all Tailwind utilities through the cn helper in src/lib/utils.ts.

The JCodesMore/ai-website-cloner-template repository is built to bridge AI-extracted website assets and a modern React UI layer. After the /clone-website skill runs, you receive SVG icons and design tokens that you can integrate with shadcn/ui component primitives already scaffolded in the template. This guide covers the exact file paths, utility functions, and composition patterns defined in the source code to make that integration seamless.

Architecture Overview

The template separates three concerns that let you plug cloned assets directly into the UI layer.

  • cn utility in src/lib/utils.ts — This function uses clsx and tailwind-merge to merge Tailwind class lists without conflicts. Every primitive relies on it to compose final class strings.
  • Shadcn/ui primitives in src/components/ui/* — These are thin wrappers around Radix primitives that expose a cva-based variant API. For example, src/components/ui/button.tsx wraps @base-ui/react/button and applies variant classes via cn.
  • Extracted assets — SVG icons, images, and custom design-token values generated by the AI agents are placed under src/components/icons.tsx (created at clone time) and public/images/….

Because every primitive ultimately renders a plain HTML element or Radix component, extracted content can be injected anywhere a className or children prop is accepted.

Generated Artifacts After Cloning

When the cloning pipeline completes, it produces two categories of artifacts:

  1. Design tokens — Colors, radii, spacing, and typography values that map directly onto Tailwind CSS classes or CSS custom properties.
  2. SVG icons — Visual elements extracted from the source site that correspond to buttons, logos, and decorative graphics.

These artifacts are type-safe by convention: the icons module follows the same pattern as shadcn/ui’s own icon components, and the tokens are applied through className strings that cn resolves.

Step-by-Step Integration

Generate the Icons Module

The first step is to create src/components/icons.tsx at clone time. Each extracted SVG is exported as a React component using forwardRef so it can receive standard SVG props and refs.

// src/components/icons.tsx (generated)
import { forwardRef } from "react";

export const Logo = forwardRef<SVGSVGElement>((props, ref) => (
  <svg ref={ref} viewBox="0 0 24 24" {...props}>
    {/* …extracted path data… */}
  </svg>
));

// repeat for each SVG extracted from the target site

This module mirrors the pattern expected by shadcn/ui consumers: import an icon and pass it as a child or through an icon prop.

Use Icons Inside UI Components

With the icons module in place, you can compose them directly inside any primitive. Because shadcn/ui components accept children, no internal changes to the primitive are required.

// Example usage in a page or component
import { Button } from "@/components/ui/button";
import { Logo } from "@/components/icons";

export default function Example() {
  return (
    <Button variant="outline" size="sm">
      <Logo className="mr-2 size-4" />
      Sign in
    </Button>
  );
}

The Button primitive in src/components/ui/button.tsx remains untouched; the extracted icon is injected through composition.

Extend Variants with Design Tokens

Extracted design tokens become new variants inside the existing cva configuration. In src/components/ui/button.tsx, the buttonVariants object can accept additional token-driven classes without breaking the original API.

// src/components/ui/button.tsx – extend buttonVariants
import { cva } from "class-variance-authority";

const buttonVariants = cva(
  "group/button inline-flex ...", // existing base classes
  {
    variants: {
      variant: {
        default: "bg-primary text-primary-foreground",
        // NEW variant derived from extracted token
        accent: "bg-[var(--extracted-accent-bg)] text-[var(--extracted-accent-fg)]",
        // keep existing ones…
      },
      // size variants stay the same
    },
    defaultVariants: { variant: "default", size: "default" },
  }
);

This keeps the UI code type-safe while allowing the cloned aesthetic to propagate through the same variant API.

Merge Classes Safely with cn

The cn utility exported from src/lib/utils.ts guarantees that Tailwind class merging rules are respected. Use it whenever you combine generated token classes with user-provided or primitive classes.

import { cn } from "@/lib/utils";

const cardClass = cn(
  "rounded-lg p-4",
  "bg-[var(--extracted-card-bg)]", // token from extraction
  customClass // user-provided class
);

According to the source code in src/lib/utils.ts, cn(...inputs) delegates to clsx for conditional logic and tailwind-merge for deduplication, so duplicate bg- or p- utilities never conflict.

Practical Code Examples

Page-Level Composition

The file src/app/page.tsx demonstrates how to mix extracted icons, extended button variants, and token-driven layout classes in a single view.

/* src/app/page.tsx */
import { Button } from "@/components/ui/button";
import { Logo } from "@/components/icons";
import { cn } from "@/lib/utils";

export default function Home() {
  return (
    <main className="flex min-h-screen items-center justify-center gap-4">
      <Button variant="accent" size="lg">
        <Logo className="mr-2 size-5" />
        Get Started
      </Button>

      {/* A card that uses extracted design tokens */}
      <section
        className={cn(
          "rounded-xl p-6 shadow-md",
          "bg-[var(--extracted-card-bg)]",
          "border-[var(--extracted-card-border)]"
        )}
      >
        <h2 className="text-xl font-bold">Welcome</h2>
        <p className="mt-2 text-muted-foreground">
          This UI is built from assets cloned from the original site.
        </p>
      </section>
    </main>
  );
}

Primitive-Level Token Injection

You can also bake extracted tokens directly into other shadcn/ui primitives. Below is an Input component that references cloned color variables for its background and border.

/* src/components/ui/input.tsx */
import { Input as InputPrimitive } from "@base-ui/react/input";
import { cn } from "@/lib/utils";

export function Input({ className, ...props }: InputPrimitive.Props) {
  return (
    <InputPrimitive
      className={cn(
        "border rounded-md px-3 py-2",
        "bg-[var(--extracted-input-bg)]",
        "border-[var(--extracted-input-border)]",
        className
      )}
      {...props}
    />
  );
}

This pattern ensures the extracted palette is respected even at the lowest-level wrapper.

Key Files and Their Roles

  • src/lib/utils.ts — Houses the cn utility that merges Tailwind classes safely using clsx and tailwind-merge.
  • src/components/ui/button.tsx — The shadcn/ui primitive wrapping @base-ui/react/button; exposes buttonVariants via cva.
  • src/components/icons.tsx — Generated at clone time; exports each extracted SVG as a forwardRef React component.
  • src/app/page.tsx — Example page composing extracted icons and design tokens with shadcn/ui primitives.
  • src/app/layout.tsx — Global layout loading Tailwind and font configuration for the entire application.

Summary

  • Generate src/components/icons.tsx to expose every extracted SVG as a reusable React component.
  • Extend cva variants in primitives such as src/components/ui/button.tsx with extracted design-token classes.
  • Use cn from src/lib/utils.ts whenever you merge Tailwind utilities to prevent conflicting class names.
  • Compose via children and className rather than editing primitive internals, keeping the architecture clean and type-safe.
  • Reference CSS variables like var(--extracted-accent-bg) directly in variant definitions to reflect the cloned site's design.

Frequently Asked Questions

Can I add extracted icons to any shadcn/ui primitive?

Yes. Because shadcn/ui primitives render standard HTML or Radix elements, they accept children and className props natively. You can import any icon from src/components/icons.tsx and place it inside a Button, Dialog, or DropdownMenu without modifying the primitive source.

Where should the extracted design tokens live?

The tokens are consumed as CSS custom properties referenced inside className strings. You can define these variables in a global stylesheet or in src/app/layout.tsx, then reference them in variant objects like buttonVariants or inside cn calls across src/components/ui/*.

Does the cn utility handle duplicate Tailwind classes?

Yes. The cn function in src/lib/utils.ts passes inputs through tailwind-merge, which automatically resolves duplicate utilities. For example, if "bg-red-500" and "bg-blue-500" are both supplied, the last one wins and no invalid CSS is produced.

Do I need to modify Radix or base-ui imports to use cloned assets?

No. The template wraps primitives such as @base-ui/react/button and @base-ui/react/input in local files under src/components/ui/. You only edit the wrapper files to inject token classes; the underlying Radix or base-ui imports remain unchanged.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →