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

@bquery/bquery

v1.6.0

Published

The jQuery for the Modern Web Platform - Zero build, TypeScript-first library with reactivity, components, and motion

Downloads

1,057

Readme

Repo Stars Issues License npm Bundle Size unpkg CodeFactor JsDelivr

The jQuery for the modern Web Platform.

bQuery.js is a slim, TypeScript-first library that combines jQuery's direct DOM workflow with modern features like reactivity, async data composables, Web Components, motion utilities, routing, stores, and declarative views — without a mandatory build step.

Highlights

  • Zero-build capable: runs directly in the browser; build tools are optional.
  • Async data built-in: fetch and async state composables integrate directly with signals.
  • Security-focused: DOM writes are sanitized by default; Trusted Types supported.
  • Modular: the core stays small; extra modules are opt-in.
  • TypeScript-first: clear types and strong IDE support.
  • Tree-shakeable: import only what you need.
  • Storybook-ready: default components can be previewed and developed in Storybook with dedicated story template helpers.

Installation

Via npm/bun/pnpm

# npm
npm install @bquery/bquery

# bun
bun add @bquery/bquery

# pnpm
pnpm add @bquery/bquery

Via CDN (Zero-build)

ES Modules (recommended)

<script type="module">
  import { $, signal } from 'https://unpkg.com/@bquery/bquery@1/dist/full.es.mjs';

  const count = signal(0);
  $('#counter').text(`Count: ${count.value}`);
</script>

UMD (global variable)

<script src="https://unpkg.com/@bquery/bquery@1/dist/full.umd.js"></script>
<script>
  const { $, signal } = bQuery;
  const count = signal(0);
</script>

IIFE (self-executing)

<script src="https://unpkg.com/@bquery/bquery@1/dist/full.iife.js"></script>
<script>
  const { $, $$ } = bQuery;
  $$('.items').addClass('loaded');
</script>

Import Strategies

// Full bundle (all modules)
import {
  $,
  signal,
  component,
  registerDefaultComponents,
  defineBqueryConfig,
} from '@bquery/bquery';

// Core only
import { $, $$ } from '@bquery/bquery/core';

// Core utilities (named exports, tree-shakeable)
import { debounce, merge, uid, once, utils } from '@bquery/bquery/core';

// Reactive only
import {
  signal,
  computed,
  effect,
  linkedSignal,
  persistedSignal,
  useAsyncData,
  useFetch,
  createUseFetch,
} from '@bquery/bquery/reactive';

// Components only
import {
  bool,
  component,
  defineComponent,
  html,
  registerDefaultComponents,
} from '@bquery/bquery/component';

// Motion only
import { transition, spring, animate, timeline } from '@bquery/bquery/motion';

// Security only
import { sanitize, sanitizeHtml, trusted } from '@bquery/bquery/security';

// Platform only
import { storage, cache, useCookie, definePageMeta, useAnnouncer } from '@bquery/bquery/platform';

// Router, Store, View
import { createRouter, navigate } from '@bquery/bquery/router';
import { createStore, defineStore } from '@bquery/bquery/store';
import { mount, createTemplate } from '@bquery/bquery/view';

// Storybook helpers
import { storyHtml, when } from '@bquery/bquery/storybook';

Modules at a glance

| Module | Description | Size (gzip) | | ------------- | -------------------------------------------------- | ----------- | | Core | Selectors, DOM manipulation, events, utilities | ~11.3 KB | | Reactive | signal, computed, effect, async data/fetch | ~0.3 KB | | Component | Lightweight Web Components with props + defaults | ~1.9 KB | | Motion | View transitions, FLIP, timelines, scroll, springs | ~4.0 KB | | Security | HTML sanitizing, Trusted Types, CSP | ~0.7 KB | | Platform | Storage, cache, cookies, meta, announcers, config | ~2.2 KB | | Router | SPA routing, navigation guards, history API | ~2.2 KB | | Store | Signal-based state management, persistence | ~0.3 KB | | View | Declarative DOM bindings, directives | ~4.3 KB |

Storybook authoring helpers are also available as a dedicated entry point via @bquery/bquery/storybook.

Quick examples

Core – DOM & events

import { $, $$ } from '@bquery/bquery/core';

$('#save').on('click', (event) => {
  console.log('Saved', event.type);
});

$('#list').delegate('click', '.item', (event, target) => {
  console.log('Item clicked', target.textContent);
});

$('#box').addClass('active').css({ opacity: '0.8' }).attr('data-state', 'ready');

const color = $('#box').css('color');

if ($('#el').is('.active')) {
  console.log('Element is active');
}

$$('.container').find('.item').addClass('found');

Reactive – signals

import {
  signal,
  computed,
  effect,
  batch,
  watch,
  readonly,
  linkedSignal,
} from '@bquery/bquery/reactive';

const count = signal(0);
const doubled = computed(() => count.value * 2);

effect(() => {
  console.log('Count changed', count.value);
});

watch(count, (newVal, oldVal) => {
  console.log(`Changed from ${oldVal} to ${newVal}`);
});

const readOnlyCount = readonly(count);

batch(() => {
  count.value++;
  count.value++;
});

count.dispose();

const first = signal('Ada');
const last = signal('Lovelace');
const fullName = linkedSignal(
  () => `${first.value} ${last.value}`,
  (next) => {
    const [nextFirst, nextLast] = next.split(' ');
    first.value = nextFirst ?? '';
    last.value = nextLast ?? '';
  }
);

fullName.value = 'Grace Hopper';

Reactive – async data & fetch

import { signal, useFetch, createUseFetch } from '@bquery/bquery/reactive';

const userId = signal(1);

const user = useFetch<{ id: number; name: string }>(() => `/users/${userId.value}`, {
  baseUrl: 'https://api.example.com',
  watch: [userId],
  query: { include: 'profile' },
});

const useApiFetch = createUseFetch({
  baseUrl: 'https://api.example.com',
  headers: { 'x-client': 'bquery-readme' },
});

const settings = useApiFetch<{ theme: string }>('/settings');

console.log(user.pending.value, user.data.value, settings.error.value);

Components – Web Components

import {
  bool,
  component,
  defineComponent,
  html,
  registerDefaultComponents,
  safeHtml,
} from '@bquery/bquery/component';
import { sanitizeHtml, trusted } from '@bquery/bquery/security';

const badge = trusted(sanitizeHtml('<span class="badge">Active</span>'));

component('user-card', {
  props: {
    username: { type: String, required: true },
    age: { type: Number, validator: (v) => v >= 0 && v <= 150 },
  },
  state: { count: 0 },
  beforeMount() {
    console.log('About to mount');
  },
  connected() {
    console.log('Mounted');
  },
  beforeUpdate(newProps, oldProps) {
    return newProps.username !== oldProps.username;
  },
  updated(change) {
    console.log('Updated because of', change?.name ?? 'state/signal change');
  },
  onError(error) {
    console.error('Component error:', error);
  },
  render({ props, state }) {
    return safeHtml`
      <button class="user-card" ${bool('disabled', state.count > 3)}>
        ${badge}
        <span>Hello ${props.username}</span>
      </button>
    `;
  },
});

const UserCard = defineComponent('user-card-manual', {
  props: { username: { type: String, required: true } },
  render: ({ props }) => html`<div>Hello ${props.username}</div>`,
});

customElements.define('user-card-manual', UserCard);

const tags = registerDefaultComponents({ prefix: 'ui' });
console.log(tags.button); // ui-button

Storybook – authoring helpers

import { storyHtml, when } from '@bquery/bquery/storybook';

export const Primary = {
  args: { disabled: false, label: 'Save' },
  render: ({ disabled, label }) =>
    storyHtml`
      <ui-card>
        <ui-button ?disabled=${disabled}>${label}</ui-button>
        ${when(!disabled, '<small>Ready to submit</small>')}
      </ui-card>
    `,
};

Motion – animations

import { animate, keyframePresets, spring, transition } from '@bquery/bquery/motion';

await transition({
  update: () => {
    $('#content').text('Updated');
  },
  classes: ['page-transition'],
  types: ['navigation'],
  skipOnReducedMotion: true,
});

await animate(card, {
  keyframes: keyframePresets.pop(),
  options: { duration: 240, easing: 'ease-out' },
});

const x = spring(0, { stiffness: 120, damping: 14 });
x.onChange((value) => {
  element.style.transform = `translateX(${value}px)`;
});
await x.to(100);

Security – sanitizing

import { sanitize, escapeHtml, sanitizeHtml, trusted } from '@bquery/bquery/security';
import { safeHtml } from '@bquery/bquery/component';

const safeMarkup = sanitize(userInput);
const safe = sanitize('<form id="cookie">...</form>');
const urlSafe = sanitize('<a href="java\u200Bscript:alert(1)">click</a>');
const secureLink = sanitize('<a href="https://external.com" target="_blank">Link</a>');
const safeSrcset = sanitize('<img srcset="safe.jpg 1x, javascript:alert(1) 2x">');
const safeForm = sanitize('<form action="javascript:alert(1)">...</form>');
const escaped = escapeHtml('<script>alert(1)</script>');
const icon = trusted(sanitizeHtml('<span class="icon">♥</span>'));
const button = safeHtml`<button>${icon}<span>Save</span></button>`;

Platform – config, cookies & accessibility

import {
  defineBqueryConfig,
  useCookie,
  definePageMeta,
  useAnnouncer,
  storage,
  notifications,
} from '@bquery/bquery/platform';

defineBqueryConfig({
  fetch: { baseUrl: 'https://api.example.com' },
  transitions: { skipOnReducedMotion: true, classes: ['page-transition'] },
  components: { prefix: 'ui' },
});

const theme = useCookie<'light' | 'dark'>('theme', { defaultValue: 'light' });
const cleanupMeta = definePageMeta({ title: 'Dashboard' });
const announcer = useAnnouncer();

theme.value = 'dark';
announcer.announce('Preferences saved');
cleanupMeta();

const local = storage.local();
await local.set('theme', theme.value);

const permission = await notifications.requestPermission();
if (permission === 'granted') {
  notifications.send('Build complete', {
    body: 'Your docs are ready.',
  });
}

Router – SPA navigation

import { effect } from '@bquery/bquery/reactive';
import { createRouter, navigate, currentRoute } from '@bquery/bquery/router';

const router = createRouter({
  routes: [
    { path: '/', name: 'home', component: HomePage },
    { path: '/user/:id', name: 'user', component: UserPage },
    { path: '*', component: NotFound },
  ],
});

router.beforeEach(async (to) => {
  if (to.path === '/admin' && !isAuthenticated()) {
    await navigate('/login');
    return false;
  }
});

effect(() => {
  console.log('Current path:', currentRoute.value.path);
});

Store – state management

import {
  createStore,
  createPersistedStore,
  defineStore,
  mapGetters,
  watchStore,
} from '@bquery/bquery/store';

const counterStore = createStore({
  id: 'counter',
  state: () => ({ count: 0, name: 'Counter' }),
  getters: {
    doubled: (state) => state.count * 2,
  },
  actions: {
    increment() {
      this.count++;
    },
  },
});

const settingsStore = createPersistedStore({
  id: 'settings',
  state: () => ({ theme: 'dark', language: 'en' }),
});

const useCounter = defineStore('counter', {
  state: () => ({ count: 0 }),
  getters: {
    doubled: (state) => state.count * 2,
  },
  actions: {
    increment() {
      this.count++;
    },
  },
});

const counter = useCounter();
const getters = mapGetters(counter, ['doubled']);

watchStore(
  counter,
  (state) => state.count,
  (value) => {
    console.log('Count changed:', value, getters.doubled);
  }
);

View – declarative bindings

import { mount, createTemplate } from '@bquery/bquery/view';
import { signal } from '@bquery/bquery/reactive';

const count = signal(0);
const items = signal(['Apple', 'Banana', 'Cherry']);

mount('#app', {
  count,
  items,
  increment: () => count.value++,
});

Browser Support

| Browser | Version | Support | | ------- | ------- | ------- | | Chrome | 90+ | ✅ Full | | Firefox | 90+ | ✅ Full | | Safari | 15+ | ✅ Full | | Edge | 90+ | ✅ Full |

No IE support by design.

Documentation

Local Development

# Install dependencies
bun install

# Start VitePress docs
bun run dev

# Run Storybook
bun run storybook

# Run tests
bun test

# Build library
bun run build

# Build docs
bun run build:docs

# Generate API documentation
bun run docs:api

Project Structure

bQuery.js
├── src/
│   ├── core/       # Selectors, DOM ops, events, utils
│   ├── reactive/   # Signals, computed, effects, async data
│   ├── component/  # Web Components helper + default library
│   ├── motion/     # View transitions, FLIP, springs
│   ├── security/   # Sanitizer, CSP, Trusted Types
│   ├── platform/   # Storage, cache, cookies, meta, config
│   ├── router/     # SPA routing, navigation guards
│   ├── store/      # State management, persistence
│   └── view/       # Declarative DOM bindings
├── docs/           # VitePress documentation
├── .storybook/     # Storybook config
├── stories/        # Component stories
├── tests/          # bun:test suites
└── dist/           # Built files (ESM, UMD, IIFE)

Contributing

See CONTRIBUTING.md for guidelines.

AI Agent Support

This project provides dedicated context files for AI coding agents:

License

MIT – See LICENSE.md for details.