Skip to content

Getting Started

Pencel is a build-agnostic Web Component compiler that transforms TypeScript decorators into vanilla Web Components. Write once, output everywhere—React, Angular, Vue, or vanilla Web Components from a single source.

If you’re wondering whether Pencel is right for your project, see Why Pencel? for a comparison with other tools and use-case guidance.

Key benefits:

  • 🎯 Write once, deploy everywhere – Output to React, Angular, Vue, or vanilla Web Components from a single source
  • Zero runtime overhead – Compiles to standard Web Components with minimal footprint
  • 🔧 Framework-agnostic – Works with any build tool (Vite, Webpack, esbuild, etc.)
  • 📦 TypeScript-first – Full type safety and IDE support

Install the Pencel runtime to start building Web Components:

Terminal window
npm install @pencel/runtime

Creating a Web Component with Pencel requires no configuration—just decorators and TypeScript.

Create a new file components/Hello.tsx with a simple component:

import { Component, Prop } from '@pencel/runtime';
@Component({
tag: 'hello'
})
export class Hello extends HTMLElement {
@Prop() name: string = 'World';
render() {
return <span>Hello {this.name}</span>;
}
}

The @Component decorator registers your class as a custom element with the default pen namespace. The resulting tag is pen-hello.

Add it to your HTML file:

<pen-hello name="Max"></pen-hello>

Or in JSX/TSX:

<pen-hello name="Max" />

You’ve created your first Web Component! Explore deeper:

  • Decorators – Learn @Prop, @Event, @Method, and advanced features
  • Configuration – Configure your pencel.config.ts for production
  • Framework Outputs – Generate React, Angular, or Vue bindings
  • Examples – Full project examples with different frameworks

By default, Pencel outputs native Web Components. To generate framework-specific bindings (React, Angular, Vue), enable framework plugins in your configuration:

pencel.config.ts
import { defineConfig } from '@pencel/cli';
export default defineConfig({
plugins: [
{ name: 'react', options: { outputPath: 'out/react' } },
{ name: 'angular', options: { outputPath: 'out/angular' } }
]
});

Each plugin generates framework-specific wrappers from your components (one per source file).