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

codefolio-ui

v1.1.8

Published

Portfolio design library built with Lit Web Components. 15 ready-made components — Navbar, Terminal, Card, Timeline, Sidebar, Table and more. Works with React, Vue, Angular, Svelte, or plain HTML. Dark mode, TypeScript, zero dependencies.

Readme

codefolio-ui

Web Component UI library for React, Vue, Angular, and Svelte — built with Lit, dark mode ready, zero dependencies.

npm version license types


Overview

Docs: https://codefolio-ui.akash-desai.online/

codefolio-ui is a design system built on Lit Web Components. Every component ships as a native custom element, meaning it works in any JavaScript framework or plain HTML — with no runtime coupling to React, Vue, Angular, or Svelte.

  • 15 components covering layout, navigation, typography, data display, and inputs
  • Dark mode via CSS custom properties and a data-theme attribute on <html>
  • React wrappers via @lit/react for React 17/18 (typed props + event forwarding)
  • React 19+ native custom element support — wrappers optional
  • ESM + CJS dual build via tsup
  • Full TypeScript — every component ships .d.ts types

Requirements

| Requirement | Version | Notes | |---|---|---| | Node.js | ≥ 18 | | | npm | ≥ 7 | Peer deps auto-install on npm 7+ | | @lit/react | ^1.0.4 | Auto-installed as a peer dependency | | react + react-dom | ≥ 17 | Only needed for React projects |

@lit/react is a required peer dependency for React users. On npm 7+, it installs automatically alongside codefolio-ui. On npm 6 or older, install it manually (see below).


Installation

React projects (recommended)

Run a single command — npm 7+ will automatically install @lit/react, react, and react-dom as peer dependencies:

npm install codefolio-ui

If you are on npm 6 or older, peer dependencies do not auto-install. Run:

npm install codefolio-ui @lit/react react react-dom

Verify all three peer deps are present after install:

npm ls @lit/react react react-dom

Vue / Svelte / Angular projects

No peer dependencies needed. Install the core package only:

npm install codefolio-ui

Plain HTML / CDN

No install needed — use the jsDelivr CDN directly (see CDN usage below).


Required setup — ThemeProvider

All components depend on CSS design tokens. Without ThemeProvider mounted once in your app, components will render with no colours, no spacing, and no dark mode.

ThemeProvider injects a <style> tag into <head> containing all CSS custom properties (--cf-primary, --cf-surface, --cf-on-surface, etc.) that every component uses internally.

Place it once at the root of your app, before any other components:

// App.tsx (React)
import { ThemeProvider } from 'codefolio-ui/react'

export default function App() {
  return (
    <>
      <ThemeProvider theme="system" style={{ display: 'none' }} />
      {/* rest of your app */}
    </>
  )
}
  • theme="system" — follows the user's OS preference (light/dark). Also accepts "light" or "dark".
  • style={{ display: 'none' }} — the element renders nothing visible, hide it to avoid layout gaps.
  • The resolved theme is persisted in localStorage under the key cf-theme and survives page reloads.
  • useRef is optional — only needed if you want to call themeRef.current.toggle() programmatically.

Vue / Svelte / Angular / HTML:

<codefolio-theme-provider theme="system" style="display:none"></codefolio-theme-provider>

Usage

React 17 / 18

Import from the /react sub-path. Wrappers are generated with @lit/react so typed props, onX event handlers, and refs all work natively.

import { Button, Card, Navbar } from 'codefolio-ui/react'
import type { ButtonVariant } from 'codefolio-ui/react'

export default function App() {
  return (
    <>
      <Navbar brand="My App" variant="full" position="on-top-always" />
      <Card variant="elevated" style={{ padding: '1.5rem' }}>
        <Button variant="primary" size="lg" label="Get started" />
      </Card>
    </>
  )
}

React 19+

React 19 has native Web Component support. Both patterns are valid:

Option A — React wrappers (full TypeScript types, onX events, refs)

import { Button, Card } from 'codefolio-ui/react'

export default function App() {
  return <Button variant="primary" label="Hello" />
}

Option B — Native custom elements (no wrappers needed)

import 'codefolio-ui' // registers all custom elements

export default function App() {
  return <codefolio-button variant="primary">Hello</codefolio-button>
}

Vue / Svelte

Import the main bundle to register all custom elements, then use the HTML tags directly in your templates.

// main.ts / main.js
import 'codefolio-ui'
<!-- Vue SFC / Svelte template -->
<codefolio-button variant="primary" label="Hello"></codefolio-button>
<codefolio-card variant="elevated">
  <codefolio-text variant="title-lg">Card title</codefolio-text>
</codefolio-card>

Angular

Register all custom elements in main.ts, then add CUSTOM_ELEMENTS_SCHEMA to suppress "unknown element" warnings.

// main.ts
import 'codefolio-ui'
import { bootstrapApplication } from '@angular/platform-browser'
import { AppComponent } from './app/app.component'

bootstrapApplication(AppComponent)

Standalone component:

import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'

@Component({
  selector: 'app-root',
  standalone: true,
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
  template: `
    <codefolio-button variant="primary" label="Hello"></codefolio-button>
    <codefolio-card variant="elevated">
      <codefolio-text variant="title-lg">Card title</codefolio-text>
    </codefolio-card>
  `,
})
export class AppComponent {}

NgModule (non-standalone):

import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { AppComponent } from './app.component'

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule],
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
  bootstrap: [AppComponent],
})
export class AppModule {}

Plain HTML / CDN

<script type="module">
  import 'https://cdn.jsdelivr.net/npm/codefolio-ui/dist/index.js'
</script>

<codefolio-button variant="primary">Hello</codefolio-button>
<codefolio-card variant="elevated">
  <codefolio-text variant="body-md">Card content</codefolio-text>
</codefolio-card>

Theming

Toggle programmatically

Add a ref only if you need to call toggle() from code:

import { ThemeProvider } from 'codefolio-ui/react'
import { useRef } from 'react'

export default function App() {
  const themeRef = useRef<any>(null)

  return (
    <>
      <ThemeProvider ref={themeRef} theme="system" style={{ display: 'none' }} />
      <button onClick={() => themeRef.current?.toggle()}>Toggle theme</button>
    </>
  )
}

Or toggle directly on the DOM without a ref:

document.documentElement.setAttribute('data-theme', 'dark')
localStorage.setItem('cf-theme', 'dark') // persisted across reloads

Listen to changes

<ThemeProvider
  theme="system"
  onThemeChange={e => console.log(e.detail.theme)} // 'light' | 'dark'
  style={{ display: 'none' }}
/>

The resolved theme is persisted in localStorage under the key cf-theme and survives page reloads.


For vibe coders

Using an AI coding assistant (Cursor, Claude, Copilot, ChatGPT)? Copy the prompt below and paste it at the start of your chat. It tells the agent to read the ai.md file shipped inside the package — a complete machine-readable API reference with every component, prop, variant, and working example.

You are helping me build a UI using the codefolio-ui component library.

Before writing any code, read the full API reference at:
  node_modules/codefolio-ui/ai.md

Key rules from that file:
- Always mount <ThemeProvider theme="system" style={{ display: 'none' }} /> once at the app root — components will not render correctly without it.
- Import React components from 'codefolio-ui/react', not 'codefolio-ui'.
- Button and Chip use a label prop, not children.
- Never invent prop names or variant strings — only use the ones in ai.md.
- Table requires all 7 sub-components (Table, TableHead, TableHeadRow, TableHeadCell, TableBody, TableRow, TableCell).

Once you have read ai.md, confirm and then help me build my UI.

The ai.md file is published inside the npm package at node_modules/codefolio-ui/ai.md and is also available on the CDN at https://cdn.jsdelivr.net/npm/codefolio-ui/ai.md.


Components

| Component | Custom element | Description | |---|---|---| | Button | <codefolio-button> | 4 variants, 3 sizes, disabled state | | Chip | <codefolio-chip> | Tag, filled, and outlined chips | | Card | <codefolio-card> | Surface card — outlined, elevated, filled, glass | | Text | <codefolio-text> | Full typographic scale — display, title, body, label, eyebrow | | Navbar | <codefolio-navbar> | 4 layout variants, mobile drawer, theme toggle | | BoxGroup | <codefolio-box-group> | Bento-grid layout system | | Section | <codefolio-section> | Full-width page section with 4 background variants | | Timeline | <codefolio-timeline> | Experience / history timeline | | Outcomes | <codefolio-outcomes> | Auto-cycling metric cards | | Sidebar | <codefolio-sidebar> | Fixed scrollspy navigation sidebar | | Table | <codefolio-table> | Composable data table with muted/good cell variants | | Terminal | <codefolio-terminal> | Animated terminal command sequence | | CodeBlock | <codefolio-code-block> | Syntax-highlighted code display | | ServiceScroller | <codefolio-service-scroller> | Infinite marquee scroller | | ThemeProvider | <codefolio-theme-provider> | Light / dark / system theming |


Component API examples

Button

<Button variant="primary"   size="lg"  label="Get started" />
<Button variant="secondary" size="md"  label="Learn more" />
<Button variant="ghost"     size="sm"  label="Cancel" />
<Button variant="cta"       label="Book a call" />
<Button variant="primary"   label="Disabled" disabled />

| Prop | Type | Default | Description | |---|---|---|---| | variant | 'primary' \| 'secondary' \| 'ghost' \| 'cta' | 'primary' | Visual style | | size | 'sm' \| 'md' \| 'lg' | 'md' | Controls padding and font size | | label | string | — | Button text (required) | | disabled | boolean | false | Disables click interaction | | onClick | (e: Event) => void | — | Fires on click |

Card

<Card variant="elevated" style={{ padding: '1.5rem' }}>
  <Text variant="title-lg">Title</Text>
  <Text variant="body-sm">Description text goes here.</Text>
</Card>

| Prop | Type | Default | Description | |---|---|---|---| | variant | 'outlined' \| 'elevated' \| 'filled' \| 'glass' | 'outlined' | Surface elevation and style | | href | string | — | Renders card as <a> with hover/focus styles |

Navbar

const NAV: NavItem[] = [
  { label: 'Home',    href: '/' },
  { label: 'About',   href: '/about' },
  { label: 'Work',    href: '/work' },
  { label: 'Contact', href: '/contact' },
]

<Navbar
  variant="full"
  position="on-top-always"
  brand="My App"
  items={NAV}
  activeHref={location.pathname}
  ctaLabel="Contact"
  ctaHref="/contact"
  onClick={e => router.push(e.detail.href)}
  onThemeToggle={() => toggleDark()}
/>

| Prop | Type | Default | Description | |---|---|---|---| | variant | 'full' \| 'minimal' \| 'centered' \| 'transparent' | 'full' | Layout and visual style | | position | 'on-top-always' \| 'scrolled' \| 'static' | 'on-top-always' | CSS positioning strategy | | brand | string | — | Brand name shown left of nav | | items | NavItem[] | — | Array of { label, href } nav items (required) | | activeHref | string | — | Highlights the matching nav item | | ctaLabel | string | — | Primary CTA button label |

Table

import { Table, TableHead, TableHeadRow, TableHeadCell,
         TableBody, TableRow, TableCell } from 'codefolio-ui/react'

<Table>
  <TableHead>
    <TableHeadRow>
      <TableHeadCell>Metric</TableHeadCell>
      <TableHeadCell>Before</TableHeadCell>
      <TableHeadCell>After</TableHeadCell>
    </TableHeadRow>
  </TableHead>
  <TableBody>
    <TableRow>
      <TableCell>Load time</TableCell>
      <TableCell variant="muted">4.2s</TableCell>
      <TableCell variant="good">1.1s</TableCell>
    </TableRow>
  </TableBody>
</Table>

TableCell variant values: 'default' | 'muted' (strikethrough) | 'good' (highlighted, bold)

Sidebar

import { Sidebar } from 'codefolio-ui/react'
import type { SidebarItem } from 'codefolio-ui/react'

const SECTIONS: SidebarItem[] = [
  { id: 'intro',    label: 'Introduction', icon: 'home'        },
  { id: 'approach', label: 'Approach',     icon: 'lightbulb'   },
  { id: 'outcomes', label: 'Outcomes',     icon: 'trending_up' },
]

<Sidebar
  items={SECTIONS}
  title="On this page"
  topOffset={80}
  onSidebarChange={e => console.log(e.detail.id)}
/>

<section id="intro">...</section>
<section id="approach">...</section>
<section id="outcomes">...</section>

The sidebar uses IntersectionObserver to automatically highlight the active section as the user scrolls. Hidden below 1024px — pair with a mobile nav pattern for small screens.

Terminal

import { Terminal } from 'codefolio-ui/react'
import type { TermSequenceItem } from 'codefolio-ui/react'

const SEQ: TermSequenceItem[] = [
  {
    dir: '~/project',
    cmd: 'npm install codefolio-ui',
    out: ['added 1 package in 0.8s', 'found 0 vulnerabilities'],
  },
  {
    dir: '~/project',
    cmd: 'npm run build',
    out: ['⚡  Build success in 74ms', 'dist/index.js  97 KB'],
  },
]

<Terminal sequence={SEQ} />

Package exports

| Import path | Contents | |---|---| | codefolio-ui | All custom elements (registers on import) | | codefolio-ui/react | React wrappers + TypeScript types | | codefolio-ui/styles | CSS design token stylesheet |


Development

# Install dependencies
npm install

# Build the library (ESM + CJS)
npm run build

# Watch mode
npm run build:watch

# Type check
npm run type-check

# Lint
npm run lint

# Storybook
npm run storybook

Browser support

All modern browsers that support Web Components v1 (Chrome, Firefox, Safari, Edge). No polyfills required.


License

MIT — see LICENSE for details.


Author

Built by Akash Desai