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

@cathode-ui/vue

v0.1.0

Published

Cathode UI — retro-future Vue 3 design system with motion, haptics, sound, and AI-native surfaces. Sibling of @cathode-ui/react. Pulls the same manifest + tokens; framework-idiomatic Vue components. Phase 4b in progress — component coverage expands over t

Readme

@cathode-ui/vue

Retro-future Vue 3 design system. Full framework-mirror of @cathode-ui/react: same 45 primitives, same tokens, same manifest, same motion/haptic/sound philosophy — implemented as idiomatic Vue SFCs (<script setup> + <template>).

By Madhan Raj.

Docs → · React package →

Install

npm install @cathode-ui/vue

Peer dep: vue >= 3.3.

AI-native

AI coding agents (Claude Code, Cursor, Windsurf, Codex, VS Code Copilot) can query the Cathode @cathode-ui/mcp server with framework: "vue" and get Vue-idiomatic imports and template snippets for every component — no prompt engineering needed. The manifest ships a vue adapter for all 45 primitives.

What's inside

45 primitives across 8 clusters, matching the React package component-for-component:

  • Layout — TerminalFrame, Card, Stack, Accordion, HazardStripes
  • Forms — Button, TextField, TextArea, Select, Checkbox, RadioGroup, Toggle, Counter, SearchBar, FormField, Chips
  • Data — Badge, Tag, Avatar, Kbd, CodeBlock, Table, StatusTile, DotLeader, Pill
  • Navigation — Tabs, Breadcrumbs, Menu, Pagination
  • Feedback — ProgressBar, Loader, Skeleton, PixelBar, ActivityBar, SignalBars, PulsingDot, Toast
  • Overlays — Dialog, Drawer, Popover, Tooltip
  • AI — Chat
  • Retro — ScanLine, TypewriterText, Countdown

Opt-in AI surface on TextField (ghost-text suggest), SearchBar (semantic search), Button (AI action routing), plus Chat as a first-class component. Apps plug in their own CathodeAIProvider via <CathodeProvider :ai="provider"> — Cathode stays provider-agnostic.

Accessibility

Every primitive inherits the same WCAG 2.0/2.1 A+AA-compliant markup as the React package — ARIA roles, keyboard navigation, focus management, form-field labelling via Vue's provide/inject.

Vue vs React API deltas

Same 45 components, same prop names wherever possible — but Vue idioms pull a few surfaces apart from their React twins. If you're porting a Cathode-React app to Vue, scan this table first.

v-model replaces value + onChange

Every controlled input uses v-model instead of the React value + onChange pair. Applies to: TextField, TextArea, Select, Checkbox, RadioGroup, Toggle, Counter, Tabs, Pagination, Accordion (via v-model:expandedIds), Popover (via v-model:open).

<!-- Vue -->              <!-- React equivalent -->
<Toggle v-model="armed" />   <Toggle value={armed} onChange={setArmed} />

Events replace on* handler props

@click, @select, @remove, @close, @complete, @sortChange, @rowClick, @actionResult, @done — Cathode-Vue emits events where React accepted onX function props.

<Button variant="primary" @click="save">SAVE</Button>
<Dialog :open="open" @close="open = false">…</Dialog>

Slots replace ReactNode props

Where React accepts a ReactNode prop (icon, children, trigger), Vue uses named or default slots.

| Component | React (prop) | Vue (slot) | |---|---|---| | Button | icon={<Icon/>} | <template #icon><Icon/></template> | | Pill | icon={<Icon/>} | <template #icon><Icon/></template> | | StatusTile | icon={<Icon/>} | <template #icon><Icon/></template> | | Menu | trigger={<Button/>} | <template #trigger><Button/></template> | | Popover | trigger={<Button/>} | <template #trigger><Button/></template> | | SearchBar | icon={<Icon/>} | <template #icon><Icon/></template> (plus showIcon prop for the default) | | Accordion | items[].content: ReactNode | <template #default="{ item }">…</template> or item.content string | | Table | columns[].render(row, i) | <template #cell-<key>="{ row, value }">…</template> |

Explicit clickable replaces "listener present"

React's Card and StatusTile swap to a <button> when you pass onClick. Vue has no prop-introspection equivalent, so both accept an explicit clickable prop:

<Card clickable @click="open" aria-label="Show details">…</Card>
<StatusTile clickable @click="talk" title="TALK" subtitle="HOLD">
  <template #icon><IconBroadcast/></template>
</StatusTile>

Removable Tag

React: pass onRemove={fn} — the × button appears. Vue: set the removable prop and listen for @remove:

<Tag accent="info" removable @remove="drop('geodesy')">GEODESY</Tag>

Button AI result

React exposes onActionResult(result) as a prop; Vue emits actionResult:

<Button :ai="{ action: 'summarize', context: { id } }" @actionResult="onResult">
  EXPLAIN
</Button>

Accordion defaultExpandedIds + v-model:expandedIds

React is either uncontrolled (defaultExpandedIds) or controlled (expandedIds + onExpandedChange). Vue uses v-model:expandedIds for control:

<Accordion :items="items" v-model:expandedIds="expandedIds" />

Boolean props — pass as false is legal

Unlike some Vue libraries, Cathode-Vue correctly distinguishes "prop not passed" from "prop explicitly false" for open-style props. Controlled <Popover :open="false" @update:open="…" /> behaves the way you expect.

AI composables instead of hooks

useAiSuggest, useAiChat, useAiAction are Vue composables returning reactive refs (not [value, setter] tuples):

const { suggestion, accept } = useAiSuggest(prefixRef, { enabled: enabledRef });
const { messages, send, streaming } = useAiChat();

Setup

// main.ts
import { createApp } from 'vue';
import App from './App.vue';

import '@cathode-ui/vue/tokens.css';   // CSS variables + dark/light
import '@cathode-ui/vue/fonts.css';    // JetBrains Mono (optional)
import '@cathode-ui/vue/styles.css';   // compiled component rules

createApp(App).mount('#app');
<!-- App.vue -->
<script setup lang="ts">
import { ref } from 'vue';
import {
  CathodeProvider, TerminalFrame, Stack, Button,
  Toggle, Counter, DotLeader, PulsingDot,
} from '@cathode-ui/vue';

const armed = ref(false);
const wpm   = ref(12);
</script>

<template>
  <CathodeProvider theme="dark" motion="strong">
    <TerminalFrame title="TELEMETRY" accent="info">
      <Stack :gap="8">
        <Stack direction="row" :gap="8" align="center">
          <PulsingDot color="var(--cathode-color-success)" />
          <span>LIVE</span>
        </Stack>
        <DotLeader label="LATENCY" value="42 MS" />
        <DotLeader label="STATE"   value="HEALTHY" />
        <Toggle  v-model="armed" label="ARMED" accent="danger" />
        <Counter v-model="wpm"   :min="5" :max="40" label="WPM" />
        <Button  variant="primary" @click="onSave">SAVE</Button>
      </Stack>
    </TerminalFrame>
  </CathodeProvider>
</template>

<CathodeProvider> accepts: theme (auto / dark / light), motion (none / subtle / strong), haptic (bool), sound (bool — default off), ai (a CathodeAIProvider instance).

Quick taste

<script setup lang="ts">
import { ref } from 'vue';
import {
  TerminalFrame, DotLeader, Button,
  TextField, FormField,
  Dialog, Chat,
} from '@cathode-ui/vue';

const callsign = ref('KA4X');
const open = ref(false);
</script>

<template>
  <TerminalFrame title="TELEMETRY" accent="info">
    <DotLeader label="LATENCY" value="42 MS" />
    <DotLeader label="STATE"   value="LIVE" valueColor="var(--cathode-color-success)" />
  </TerminalFrame>

  <FormField label="CALLSIGN" hint="4 characters, alphanumeric." required>
    <TextField v-model="callsign" />
  </FormField>

  <Button variant="primary" @click="open = true">SAVE</Button>

  <Dialog :open="open" title="SAVED" @close="open = false">
    <p>Callsign {{ callsign }} registered.</p>
  </Dialog>
</template>

Author

Built by Madhan Raj.

License

MIT.