npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@damarkuncoro/ui-renderers

v0.1.2

Published

Contract-driven React renderers for the CDMA architecture

Readme

@damarkuncoro/ui-renderers

Dynamic component renderers for contract-based UI generation, enabling runtime component creation from configuration.

📦 Installation

npm install @damarkuncoro/ui-renderers @damarkuncoro/ui-core @damarkuncoro/ui-components

🎯 What are Renderers?

Renderers enable dynamic UI generation based on contracts. Instead of hardcoding components, you define UI structure through configuration that gets rendered at runtime.

Key Benefits

  • Dynamic UI: Generate interfaces from configuration
  • Contract Compliance: Automatic validation against contracts
  • Runtime Flexibility: Change UI without code redeployment
  • Type Safety: Full TypeScript support with contract validation

🚀 Basic Usage

Simple Component Rendering

import { ContractRenderer } from '@damarkuncoro/ui-renderers';
import { buttonContract } from '@damarkuncoro/ui-core/contracts';

function DynamicButton() {
  const runtimeProps = {
    variant: 'primary',
    size: 'md',
    children: 'Click me',
    onClick: () => console.log('Button clicked!')
  };

  return (
    <ContractRenderer
      contract={buttonContract}
      runtimeProps={runtimeProps}
    />
  );
}

Form Generation

import { ContractRenderer } from '@damarkuncoro/ui-renderers';
import { formContract } from '@damarkuncoro/ui-core/contracts';

const formConfig = {
  fields: [
    {
      contract: 'input',
      props: {
        name: 'email',
        type: 'email',
        label: 'Email Address',
        required: true,
        placeholder: 'Enter your email'
      }
    },
    {
      contract: 'input',
      props: {
        name: 'password',
        type: 'password',
        label: 'Password',
        required: true
      }
    },
    {
      contract: 'button',
      props: {
        type: 'submit',
        variant: 'primary',
        children: 'Login'
      }
    }
  ]
};

function DynamicForm() {
  return (
    <ContractRenderer
      contract={formContract}
      runtimeProps={formConfig}
    />
  );
}

🏗️ Architecture

Contract-Based Rendering

Contract Definition → Renderer Map → Component Instance
       ↓                    ↓              ↓
   Validation    →   Resolution   →   Rendering

Renderer Resolution

// Renderer map connects contracts to components
const rendererMap = {
  'ui-button': ButtonRenderer,
  'ui-input': InputRenderer,
  'ui-card': CardRenderer,
  // ... more mappings
};

📋 Advanced Usage

Custom Renderers

import { createRenderer } from '@damarkuncoro/ui-renderers';

// Create custom renderer
const CustomCardRenderer = createRenderer({
  contractId: 'custom-card',
  component: ({ title, content, ...props }) => (
    <div className="custom-card" {...props}>
      <h3 className="custom-title">{title}</h3>
      <div className="custom-content">{content}</div>
    </div>
  ),
  validate: (props) => {
    // Custom validation logic
    if (!props.title) {
      throw new Error('Title is required for custom card');
    }
  }
});

// Register custom renderer
registerRenderer('custom-card', CustomCardRenderer);

Dynamic Page Generation

import { PageRenderer } from '@damarkuncoro/ui-renderers';

const pageConfig = {
  layout: 'dashboard',
  sections: [
    {
      type: 'stats',
      components: [
        { contract: 'stats-card', props: { title: 'Revenue', value: '$45,231' } },
        { contract: 'stats-card', props: { title: 'Users', value: '12,234' } }
      ]
    },
    {
      type: 'content',
      components: [
        { contract: 'table', props: { data: tableData, columns: tableColumns } }
      ]
    }
  ]
};

function DynamicPage() {
  return <PageRenderer config={pageConfig} />;
}

Conditional Rendering

const conditionalConfig = {
  condition: 'user.role === "admin"',
  components: [
    {
      contract: 'button',
      props: { children: 'Admin Panel', variant: 'primary' }
    }
  ],
  fallback: {
    contract: 'text',
    props: { children: 'Access denied' }
  }
};

<ConditionalRenderer config={conditionalConfig} context={{ user }} />

🔧 Renderer API

ContractRenderer

interface ContractRendererProps {
  contract: ContractEntity;
  runtimeProps?: Record<string, any>;
  context?: Record<string, any>;
  onError?: (error: Error) => void;
  onSuccess?: (result: any) => void;
}

PageRenderer

interface PageRendererProps {
  config: PageConfig;
  context?: Record<string, any>;
  theme?: string;
  skin?: string;
}

interface PageConfig {
  layout?: string;
  sections: SectionConfig[];
}

interface SectionConfig {
  type: string;
  components: ComponentConfig[];
}

interface ComponentConfig {
  contract: string;
  props: Record<string, any>;
  condition?: string;
}

🎨 Integration with Themes

Theme-Aware Rendering

import { ThemeProvider } from '@damarkuncoro/ui-themes';
import { ContractRenderer } from '@damarkuncoro/ui-renderers';

function ThemedDynamicComponent() {
  return (
    <ThemeProvider skin="metronic">
      <ContractRenderer
        contract={componentContract}
        runtimeProps={componentProps}
      />
    </ThemeProvider>
  );
}

Skin-Specific Rendering

// Renderer can adapt based on active theme
const adaptiveRenderer = ({ contract, runtimeProps, theme }) => {
  const skin = theme.skin || 'default';

  // Different rendering logic per skin
  switch (skin) {
    case 'metronic':
      return <MetronicComponent {...runtimeProps} />;
    case 'material':
      return <MaterialComponent {...runtimeProps} />;
    default:
      return <DefaultComponent {...runtimeProps} />;
  }
};

🔒 Validation & Error Handling

Contract Validation

import { validateContractProps } from '@damarkuncoro/ui-renderers';

const contract = buttonContract;
const runtimeProps = { variant: 'invalid-variant' };

try {
  const validatedProps = validateContractProps(contract, runtimeProps);
  // Render with validated props
} catch (error) {
  console.error('Validation failed:', error.message);
  // Fallback rendering or error display
}

Error Boundaries

import { RendererErrorBoundary } from '@damarkuncoro/ui-renderers';

function SafeRenderer({ contract, runtimeProps }) {
  return (
    <RendererErrorBoundary
      fallback={(error) => (
        <div className="error-fallback">
          Failed to render component: {error.message}
        </div>
      )}
    >
      <ContractRenderer
        contract={contract}
        runtimeProps={runtimeProps}
      />
    </RendererErrorBoundary>
  );
}

📊 Performance Optimization

Memoization

import { memoizedRenderer } from '@damarkuncoro/ui-renderers';

// Automatically memoizes rendered components
const MemoizedContractRenderer = memoizedRenderer(ContractRenderer);

Lazy Loading

import { lazyRenderer } from '@damarkuncoro/ui-renderers';

// Load components on demand
const LazyButtonRenderer = lazyRenderer(() =>
  import('./ButtonRenderer')
);

Renderer Caching

import { createRendererCache } from '@damarkuncoro/ui-renderers';

const rendererCache = createRendererCache();

// Cache rendered components
const cachedRenderer = rendererCache.get(contract.id) ||
  rendererCache.set(contract.id, createRenderer(contract));

🧪 Testing Renderers

Unit Testing

import { render, screen } from '@testing-library/react';
import { ContractRenderer } from '@damarkuncoro/ui-renderers';
import { buttonContract } from '@damarkuncoro/ui-core/contracts';

test('renders button from contract', () => {
  const runtimeProps = {
    children: 'Test Button',
    onClick: jest.fn()
  };

  render(
    <ContractRenderer
      contract={buttonContract}
      runtimeProps={runtimeProps}
    />
  );

  const button = screen.getByRole('button', { name: 'Test Button' });
  expect(button).toBeInTheDocument();
});

Integration Testing

import { render, fireEvent, waitFor } from '@testing-library/react';
import { FormRenderer } from '@damarkuncoro/ui-renderers';

test('form submission works', async () => {
  const onSubmit = jest.fn();
  const formConfig = {
    fields: [
      { contract: 'input', props: { name: 'email', required: true } },
      { contract: 'button', props: { type: 'submit', children: 'Submit' } }
    ],
    onSubmit
  };

  render(<FormRenderer config={formConfig} />);

  const emailInput = screen.getByLabelText('email');
  const submitButton = screen.getByRole('button', { name: 'Submit' });

  fireEvent.change(emailInput, { target: { value: '[email protected]' } });
  fireEvent.click(submitButton);

  await waitFor(() => {
    expect(onSubmit).toHaveBeenCalledWith({
      email: '[email protected]'
    });
  });
});

🔧 Advanced Features

Custom Renderer Plugins

import { createRendererPlugin } from '@damarkuncoro/ui-renderers';

// Create analytics plugin
const analyticsPlugin = createRendererPlugin({
  name: 'analytics',
  beforeRender: (contract, props) => {
    // Track component render
    analytics.track('component_render', {
      contractId: contract.id,
      props: Object.keys(props)
    });
  },
  afterRender: (contract, element) => {
    // Add tracking attributes
    return React.cloneElement(element, {
      'data-analytics-id': contract.id
    });
  }
});

// Register plugin
registerRendererPlugin(analyticsPlugin);

Internationalization (i18n)

import { createI18nRenderer } from '@damarkuncoro/ui-renderers';

const i18nRenderer = createI18nRenderer({
  locale: 'id',
  translations: {
    'button.submit': 'Kirim',
    'input.placeholder': 'Masukkan teks...'
  }
});

// Use i18n-aware renderer
<i18nRenderer
  contract={buttonContract}
  runtimeProps={{
    children: 'button.submit', // Will be translated
    placeholder: 'input.placeholder'
  }}
/>

Server-Side Rendering (SSR)

import { renderToString } from 'react-dom/server';
import { SSRContractRenderer } from '@damarkuncoro/ui-renderers';

function renderPage(config) {
  const html = renderToString(
    <SSRContractRenderer config={config} />
  );

  return `
    <!DOCTYPE html>
    <html>
      <body>
        <div id="root">${html}</div>
        <script src="/client.js"></script>
      </body>
    </html>
  `;
}

📚 Use Cases

CMS-Driven Interfaces

// Content Management System integration
const cmsConfig = await fetch('/api/page-config').then(r => r.json());

function CMSPage() {
  return (
    <PageRenderer
      config={cmsConfig}
      context={{ user, permissions }}
    />
  );
}

A/B Testing Components

// Dynamic component testing
const experimentConfig = {
  experimentId: 'button-color-test',
  variants: {
    control: { contract: 'button', props: { variant: 'primary' } },
    variant1: { contract: 'button', props: { variant: 'success' } }
  }
};

<ExperimentRenderer config={experimentConfig} />

Progressive Web Apps (PWA)

// Offline-capable dynamic UI
const offlineConfig = {
  fallback: {
    contract: 'offline-message',
    props: { message: 'You are currently offline' }
  },
  components: isOnline ? onlineComponents : offlineComponents
};

<ProgressiveRenderer config={offlineConfig} />

🔄 Migration Guide

From Static to Dynamic Rendering

// Before: Static component
function UserProfile({ user }) {
  return (
    <Card>
      <Avatar src={user.avatar} />
      <div>
        <h3>{user.name}</h3>
        <p>{user.email}</p>
      </div>
    </Card>
  );
}

// After: Contract-based rendering
const userProfileConfig = {
  contract: 'card',
  props: {
    children: [
      {
        contract: 'avatar',
        props: { src: '{{user.avatar}}' }
      },
      {
        contract: 'stack',
        props: {
          children: [
            { contract: 'text', props: { variant: 'h3', children: '{{user.name}}' } },
            { contract: 'text', props: { children: '{{user.email}}' } }
          ]
        }
      }
    ]
  }
};

function DynamicUserProfile({ user }) {
  return (
    <ContractRenderer
      contract={cardContract}
      runtimeProps={userProfileConfig.props}
      context={{ user }}
    />
  );
}

🤝 Contributing

When contributing to renderers:

  1. Performance: Optimize rendering logic
  2. Error Handling: Comprehensive error boundaries
  3. Type Safety: Full TypeScript coverage
  4. Testing: Both unit and integration tests
  5. Documentation: Include usage examples

📄 License

MIT License - see LICENSE file for details.