or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

examples

edge-cases.mdreal-world-scenarios.md
index.md
tile.json

real-world-scenarios.mddocs/examples/

Real-World Scenarios

Comprehensive usage examples and agent integration patterns for shadcn.

Programmatic Component Addition Workflow

For coding agents, the typical workflow for adding components programmatically:

import { resolveRegistryItems } from 'shadcn';
import { writeFile, mkdir } from 'fs/promises';
import { dirname, join } from 'path';
import { existsSync } from 'fs';

async function addComponent(componentName: string, cwd: string) {
  try {
    // 1. Resolve component with all dependencies
    const resolved = await resolveRegistryItems([componentName], {
      config: { /* project config */ }
    });

    // 2. Install npm dependencies (use package manager of choice)
    if (resolved.dependencies && resolved.dependencies.length > 0) {
      // Example: npm install ${resolved.dependencies.join(' ')}
      // Or use child_process.exec to run package manager
    }

    // 3. Write component files
    if (resolved.files) {
      for (const file of resolved.files) {
        const filePath = join(cwd, file.path);
        const dir = dirname(filePath);
        
        // Create directory if it doesn't exist
        if (!existsSync(dir)) {
          await mkdir(dir, { recursive: true });
        }
        
        // Write file content
        await writeFile(filePath, file.content || '', 'utf-8');
      }
    }

    // 4. Update Tailwind config if needed
    if (resolved.tailwind?.config) {
      // Merge resolved.tailwind.config into tailwind.config.js
      // Use a JSON/JS parser to safely merge configurations
    }

    // 5. Update CSS if needed
    if (resolved.css) {
      // Append resolved.css to your CSS file
      // Read existing CSS, append new CSS, write back
    }

    // 6. Set environment variables if needed
    if (resolved.envVars) {
      // Add to .env file
      // Read existing .env, merge new vars, write back
    }

    // 7. Handle fonts if present
    if (resolved.fonts) {
      // Process font items (e.g., add to next/font configuration)
    }

    return { success: true, resolved };
  } catch (error) {
    // Handle errors appropriately
    throw error;
  }
}

Configuration Discovery

Discover and load configuration from components.json:

import { getRegistriesConfig } from 'shadcn';
import { findUp } from 'find-up';
import { dirname } from 'path';

async function discoverConfig(cwd: string = process.cwd()) {
  // Find components.json in current or parent directories
  const configPath = await findUp('components.json', { cwd });
  
  if (!configPath) {
    throw new Error('components.json not found. Run: npx shadcn init');
  }
  
  const configDir = dirname(configPath);
  const { registries } = await getRegistriesConfig(configDir);
  
  return { configPath, configDir, registries };
}

Error Recovery Patterns

Handle errors gracefully with recovery suggestions:

import {
  getRegistryItems,
  RegistryNotFoundError,
  RegistryNotConfiguredError,
  ConfigMissingError,
  RegistryFetchError,
  RegistryUnauthorizedError
} from 'shadcn/registry';
import { searchRegistries } from 'shadcn/registry';

async function safeGetRegistryItems(items: string[], cwd?: string) {
  try {
    return await getRegistryItems(items, { config: { /* ... */ } });
  } catch (error) {
    if (error instanceof ConfigMissingError) {
      // Suggest initialization
      throw new Error('Project not initialized. Run: npx shadcn init');
    } else if (error instanceof RegistryNotConfiguredError) {
      // Suggest registry configuration
      throw new Error(`Registry not configured. Add to components.json: ${error.suggestion}`);
    } else if (error instanceof RegistryNotFoundError) {
      // Try to find similar items via search
      const searchTerm = items[0].split('/').pop() || items[0];
      const searchResults = await searchRegistries(['@shadcn'], {
        query: searchTerm,
        limit: 5
      });
      
      if (searchResults.items.length > 0) {
        throw new Error(
          `Item not found: ${items[0]}. Did you mean: ${searchResults.items.map(i => i.addCommandArgument).join(', ')}?`
        );
      }
      
      throw new Error(`Item not found: ${items[0]}. Try: npx shadcn search ${searchTerm}`);
    } else if (error instanceof RegistryUnauthorizedError) {
      // Check for missing environment variables
      throw new Error(
        `Authentication required. Check registry configuration and ensure required environment variables are set.`
      );
    } else if (error instanceof RegistryFetchError) {
      // Network error - suggest retry
      throw new Error(`Network error: ${error.message}. Please check your connection and try again.`);
    }
    throw error;
  }
}

Handling Circular Dependencies

Detect and handle circular dependencies:

import { resolveRegistryItems } from 'shadcn';
import { RegistryError } from 'shadcn/registry';

async function safeResolveItems(items: string[]) {
  try {
    return await resolveRegistryItems(items);
  } catch (error) {
    if (error instanceof RegistryError && error.code === 'VALIDATION_ERROR') {
      // Check if error message indicates circular dependency
      if (error.message.includes('circular') || error.message.includes('dependency')) {
        throw new Error(
          `Circular dependency detected in registry items: ${items.join(', ')}. ` +
          `This usually indicates a registry configuration issue.`
        );
      }
    }
    throw error;
  }
}

Batch Operations with Error Handling

Process multiple items with partial failure handling:

import { getRegistryItems } from 'shadcn';
import { RegistryNotFoundError } from 'shadcn/registry';

async function batchGetItems(itemNames: string[]) {
  const results: Array<{ name: string; item?: any; error?: string }> = [];
  
  // Process items individually to handle partial failures
  for (const itemName of itemNames) {
    try {
      const [item] = await getRegistryItems([itemName]);
      results.push({ name: itemName, item });
    } catch (error) {
      if (error instanceof RegistryNotFoundError) {
        results.push({ name: itemName, error: `Not found: ${error.message}` });
      } else {
        results.push({ name: itemName, error: `Error: ${error.message}` });
      }
    }
  }
  
  return results;
}

Workspace/Monorepo Support

Handle multiple components.json files in workspace:

import { getRegistriesConfig } from 'shadcn';
import { findUp } from 'find-up';
import { dirname } from 'path';

async function getWorkspaceConfigs(rootDir: string) {
  // Find all components.json files in workspace
  const configs: Array<{ path: string; config: any }> = [];
  
  // Search for components.json in root and subdirectories
  let currentDir = rootDir;
  while (currentDir) {
    const configPath = await findUp('components.json', { cwd: currentDir });
    if (configPath) {
      const configDir = dirname(configPath);
      const { registries } = await getRegistriesConfig(configDir);
      configs.push({ path: configPath, config: { registries } });
      
      // Move to parent directory to find other configs
      const parentDir = dirname(configDir);
      if (parentDir === currentDir) break; // Reached filesystem root
      currentDir = parentDir;
    } else {
      break;
    }
  }
  
  return configs;
}

Component Search and Discovery

Search for components and get suggestions:

import { searchRegistries } from 'shadcn/registry';

async function findComponents(query: string) {
  const results = await searchRegistries(['@shadcn'], {
    query,
    limit: 10
  });
  
  return results.items.map(item => ({
    name: item.name,
    description: item.description,
    type: item.type,
    addCommand: `npx shadcn add ${item.addCommandArgument}`
  }));
}

Non-Interactive CLI Usage

Use CLI commands programmatically with proper exit code handling:

import { exec } from 'child_process';
import { promisify } from 'util';

const execAsync = promisify(exec);

async function addComponentCLI(componentName: string, cwd: string) {
  try {
    const { stdout, stderr } = await execAsync(
      `npx shadcn add ${componentName} --yes --overwrite`,
      { cwd }
    );
    
    // Exit code 0 = success
    // Exit code 1 = general error
    // Exit code 2 = configuration error
    // Exit code 3 = registry error
    // Exit code 4 = validation error
    
    return { success: true, stdout, stderr };
  } catch (error: any) {
    const exitCode = error.code;
    
    switch (exitCode) {
      case 2:
        throw new Error('Configuration error. Run: npx shadcn init');
      case 3:
        throw new Error('Registry error. Check component name and network connection');
      case 4:
        throw new Error('Validation error. Check component name format');
      default:
        throw new Error(`Error: ${error.message}`);
    }
  }
}

MCP Integration for AI Assistants

Use MCP tools for AI assistant workflows:

// MCP server provides 7 tools:
// - get_project_registries
// - list_items_in_registries
// - search_items_in_registries
// - view_items_in_registries
// - get_item_examples_from_registries
// - get_add_command_for_items
// - get_audit_checklist

// Start MCP server
// npx shadcn mcp

// Or use programmatically
import { server } from 'shadcn/mcp';
// Server is pre-configured and ready to use

See MCP Reference for complete MCP documentation.