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

lit-prompt-config

v0.3.1

Published

Embeddable Lit web component for LLM prompt configuration. The missing UI for LLM prompt management.

Readme

lit-prompt-config

npm version License: MIT

The missing UI for LLM prompt management.

A lightweight, embeddable Lit web component for managing LLM prompt configurations. Drop it into any web app — no backend required, no platform to deploy, no vendor lock-in. Just a <script> tag and a JSON object.

Features

  • Complete prompt management UI — model selection, system/user prompts, parameters, tools, response format, reasoning settings
  • Live model discovery — fetches models from OpenRouter's public API (200+ models, no API key needed)
  • Framework agnostic — works with React, Vue, Svelte, Angular, or vanilla HTML
  • Event-based testing — never touches API keys; emits ready-to-forward payloads
  • Themeable — light/dark mode with CSS custom properties
  • Tiny footprint — ~16KB gzipped (bundled version with Lit included)

Full Usage Guide — Complete integration walkthrough with diagrams, React example, database schema, and backend setup.

Quick Start (CDN)

<script type="module" src="https://unpkg.com/lit-prompt-config/dist/lit-prompt-config.bundled.js"></script>

<prompt-config id="pc"></prompt-config>

<script>
  const pc = document.getElementById('pc');

  // Listen for changes
  pc.addEventListener('prompt-change', (e) => {
    console.log('Config updated:', e.detail);
  });

  // Handle test requests
  pc.addEventListener('prompt-test', async (e) => {
    pc.setTestLoading(true);
    try {
      const response = await fetch('/api/test-prompt', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(e.detail.payload)
      });
      pc.setTestResult(await response.json());
    } catch (err) {
      pc.setTestError(err.message);
    }
  });
</script>

Installation (npm)

npm install lit-prompt-config lit
import 'lit-prompt-config';

// The <prompt-config> element is now available

Usage Examples

Basic Usage

<prompt-config
  .value=${{ model: 'anthropic/claude-sonnet-4-5', systemPrompt: 'You are helpful.' }}
  @prompt-change=${(e) => saveConfig(e.detail)}
></prompt-config>

With Provider Filtering

<prompt-config
  .providerFilter=${['anthropic', 'openai', 'google']}
></prompt-config>

Handling Test Events

The component emits prompt-test with a ready-to-forward OpenRouter payload:

pc.addEventListener('prompt-test', async (e) => {
  const { config, payload, resolvedMessages } = e.detail;

  pc.setTestLoading(true);

  // Forward to your backend (which adds the API key)
  const response = await fetch('/api/chat', {
    method: 'POST',
    body: JSON.stringify(payload)
  });

  pc.setTestResult(await response.json());
});

Storing Configs

The config is a plain JSON object — store it anywhere:

// PostgreSQL (jsonb)
await db.query('INSERT INTO prompts (id, config) VALUES ($1, $2)', [config.id, config]);

// SQLite
db.run('INSERT INTO prompts VALUES (?, ?)', [config.id, JSON.stringify(config)]);

// localStorage
localStorage.setItem(`prompt:${config.id}`, JSON.stringify(config));

API Reference

Properties

| Property | Type | Default | Description | |----------|------|---------|-------------| | value | PromptConfig | DEFAULT_CONFIG | The configuration object | | variant | 'card' \| 'full' | 'full' | Display variant: compact card or full configuration | | enabledSections | string[] | all sections | Which UI sections to show | | providerFilter | string[] | [] (all) | Filter models to specific providers | | theme | 'light' \| 'dark' \| 'auto' | 'auto' | Color theme | | labels | Partial<Labels> | {} | Override UI labels for i18n |

Events

| Event | Detail | Description | |-------|--------|-------------| | prompt-change | PromptConfig | Fired when any config value changes (debounced 250ms) | | prompt-save | PromptConfig | Fired when user clicks Save button | | prompt-test | { config, payload, resolvedMessages } | Fired when user clicks Test button |

Methods

| Method | Description | |--------|-------------| | setTestResult(result) | Display successful test response | | setTestError(error) | Display test error | | setTestLoading(loading) | Set loading state for test button | | expand() | Expand card variant to show full configuration | | collapse() | Collapse back to card view |

Config Schema

interface PromptConfig {
  id: string;                          // Unique ID for storage
  name: string;                        // Human-readable display name
  description: string;                 // What this prompt does
  provider: string;                    // Model provider (e.g., 'anthropic', 'openai')
  model: string;                       // OpenRouter model ID
  systemPrompt: string;                // System message
  userPromptTemplate: string;          // User message with {{variable}} placeholders
  temperature: number;                 // 0-2
  maxTokens: number;                   // Max response tokens
  topP: number;                        // 0-1
  topK: number;                        // 0-500
  frequencyPenalty: number;            // -2 to 2
  presencePenalty: number;             // -2 to 2
  repetitionPenalty: number;           // 0-2
  minP: number;                        // 0-1
  stopSequences: string[];             // Stop sequences
  responseFormat: 'text' | 'json_object' | 'json_schema';
  jsonSchema: object | null;           // JSON schema for structured output
  tools: ToolDefinition[];             // OpenAI-compatible tool definitions
  toolChoice: 'auto' | 'none' | 'required';
  reasoning: boolean;                  // Enable extended thinking
  reasoningEffort: 'low' | 'medium' | 'high';
  sampleInputs: Record<string, string>; // Values for template variables
  metadata: Record<string, any>;       // User-defined metadata
  inputCostPerMillion: number | null;  // Input token cost per 1M (auto-populated)
  outputCostPerMillion: number | null; // Output token cost per 1M (auto-populated)
}

Integration Helpers

The component saves configs in a provider-agnostic format. Use these helpers to convert to provider-specific API payloads.

TypeScript / JavaScript

OpenAI / OpenRouter

import { toOpenRouterPayload } from 'lit-prompt-config/helpers/openrouter';

const payload = toOpenRouterPayload(config, { article_text: '...' });

// Works with OpenRouter, OpenAI, Azure OpenAI, Ollama, LMStudio, etc.
const response = await fetch('https://openrouter.ai/api/v1/chat/completions', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${OPENROUTER_API_KEY}`,
  },
  body: JSON.stringify(payload),
});

Anthropic

import { toAnthropicPayload } from 'lit-prompt-config/helpers/anthropic';
import Anthropic from '@anthropic-ai/sdk';

const payload = toAnthropicPayload(config, { article_text: '...' });

const anthropic = new Anthropic();
const response = await anthropic.messages.create(payload);

LangChain.js

import { toPromptTemplate, getModelConfig } from 'lit-prompt-config/helpers/langchain';
import { ChatPromptTemplate } from '@langchain/core/prompts';
import { ChatOpenAI } from '@langchain/openai';

const templateConfig = toPromptTemplate(config);
const modelConfig = getModelConfig(config);

const prompt = ChatPromptTemplate.fromMessages([
  ['system', templateConfig.systemTemplate],
  ['user', templateConfig.userTemplate],
]);

const llm = new ChatOpenAI({
  ...modelConfig,
  configuration: { baseURL: 'https://openrouter.ai/api/v1' },
});

Python

OpenAI / OpenRouter

from helpers.payloads import to_openai_payload
import requests

payload = to_openai_payload(config, {"article_text": "..."})

response = requests.post(
    "https://openrouter.ai/api/v1/chat/completions",
    headers={"Authorization": f"Bearer {OPENROUTER_API_KEY}"},
    json=payload
)

Anthropic

from helpers.payloads import to_anthropic_payload
import anthropic

payload = to_anthropic_payload(config, {"article_text": "..."})

client = anthropic.Anthropic()
response = client.messages.create(**payload)

LangChain

from helpers.langchain import from_config

config = load_config_from_db()
prompt, llm = from_config(config, api_key="sk-...")

chain = prompt | llm
result = chain.invoke({"article_text": "..."})

Internationalization (i18n)

Override any UI label via the labels property. Pass only the labels you want to change—defaults are used for the rest.

<prompt-config
  .labels=${{
    testPrompt: 'Tester le prompt',
    save: 'Enregistrer',
    temperature: 'Température',
    maxTokens: 'Tokens max',
    systemPrompt: 'Prompt système',
    userPromptTemplate: 'Template utilisateur',
    advancedSettings: 'Paramètres avancés',
  }}
></prompt-config>

Available Labels

All ~60 labels can be overridden. See the full list:

import { DEFAULT_LABELS } from 'lit-prompt-config';
console.log(Object.keys(DEFAULT_LABELS));

Categories:

  • Headers: promptConfiguration, advancedConfiguration, advancedSettings
  • Buttons: import, export, save, testPrompt, testing
  • Field labels: name, description, provider, model, temperature, maxTokens, etc.
  • Placeholders: placeholderName, placeholderDescription, placeholderSystemPrompt, etc.
  • Status messages: statusSelectModel, statusAddPrompt, statusTemplateVarsEmpty
  • Dropdown options: formatText, formatJsonObject, toolChoiceAuto, reasoningLow, etc.

With i18n Libraries

Works with any i18n solution:

// react-i18next
<prompt-config .labels=${t('promptConfig', { returnObjects: true })} />

// vue-i18n
<prompt-config :labels="$tm('promptConfig')" />

// Plain JSON
import labelsEs from './locales/es.json';
<prompt-config .labels=${labelsEs} />

Theming

Theme Modes

The component supports three theme modes via the theme attribute:

<!-- Auto: follows system preference (default) -->
<prompt-config theme="auto"></prompt-config>

<!-- Force light mode -->
<prompt-config theme="light"></prompt-config>

<!-- Force dark mode -->
<prompt-config theme="dark"></prompt-config>

Custom Themes

Override CSS custom properties to create custom themes:

/* Custom brand colors */
prompt-config {
  --pc-accent: #0ea5e9;        /* Sky blue accent */
  --pc-accent-hover: #0284c7;
  --pc-accent-bg: #f0f9ff;
  --pc-radius: 12px;           /* Rounder corners */
}

/* Custom fonts */
prompt-config {
  --pc-font: 'Inter', -apple-system, sans-serif;
  --pc-font-mono: 'Fira Code', 'JetBrains Mono', monospace;
}

/* Full dark theme override */
prompt-config.my-dark-theme {
  --pc-bg: #0f172a;
  --pc-bg-section: #1e293b;
  --pc-bg-input: #0f172a;
  --pc-bg-hover: #334155;
  --pc-border: #334155;
  --pc-text: #f8fafc;
  --pc-text-secondary: #cbd5e1;
  --pc-text-muted: #64748b;
}

Available CSS Custom Properties

| Variable | Description | Light Default | Dark Default | |----------|-------------|---------------|--------------| | --pc-bg | Main background | #fafaf9 | #1c1917 | | --pc-bg-section | Section/card background | #ffffff | #292524 | | --pc-bg-input | Input/textarea background | #f5f5f4 | #1c1917 | | --pc-bg-hover | Hover state background | #e7e5e4 | #44403c | | --pc-border | Border color | #d6d3d1 | #44403c | | --pc-border-focus | Focused input border | #78716c | #a8a29e | | --pc-text | Primary text color | #1c1917 | #fafaf9 | | --pc-text-secondary | Secondary text color | #57534e | #d6d3d1 | | --pc-text-muted | Muted/hint text color | #a8a29e | #78716c | | --pc-accent | Primary accent color | #d97706 | #f59e0b | | --pc-accent-hover | Accent hover state | #b45309 | #fbbf24 | | --pc-accent-bg | Accent background | #fffbeb | rgba(69,26,3,0.2) | | --pc-danger | Error/danger color | #dc2626 | #ef4444 | | --pc-danger-bg | Error background | #fef2f2 | #450a0a | | --pc-success | Success color | #16a34a | #22c55e | | --pc-success-bg | Success background | #f0fdf4 | #052e16 | | --pc-radius | Border radius | 6px | 6px | | --pc-shadow | Box shadow | subtle | subtle | | --pc-transition | Transition timing | 150ms ease | 150ms ease | | --pc-font | Sans-serif font stack | IBM Plex Sans | IBM Plex Sans | | --pc-font-mono | Monospace font stack | IBM Plex Mono | IBM Plex Mono |

Development

# Install dependencies
npm install

# Start dev server
npm run dev

# Build
npm run build

License

MIT