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

react-ko

v3.0.0

Published

React + Knockout integration library

Readme

react-ko

en English | ja Japanese

npm version

A minimal bridge to use Knockout.js inside React components. Combine Knockout's reactivity with React's component architecture — clean, scoped, and type-safe.

Documentation — the full API, server rendering, and migration from v2.


Installation

npm install react-ko knockout

This library requires react (^18.0.0 || ^19.0.0), react-dom (^18.0.0 || ^19.0.0), and knockout (^3.5.1) as peer dependencies. The package itself has no runtime dependencies.


In one example

import ko from 'knockout'
import { KnockoutScope, useKoValue, useKoViewModel } from 'react-ko'

const viewModel = {
  name: ko.observable('Knockout'),
  items: ko.observableArray<string>([]),
}

function Greeting() {
  const vm = useKoViewModel<typeof viewModel>()
  const count = (useKoValue(vm.items) ?? []).length

  return (
    <section>
      <input data-bind="value: name, valueUpdate: 'input'" />
      <p data-bind="text: name" />
      <p>{count} items (rendered by React)</p>
    </section>
  )
}

function App() {
  return (
    <KnockoutScope viewModel={viewModel}>
      <Greeting />
    </KnockoutScope>
  )
}

KnockoutScope is the ordinary way to establish a scope: supported data-bind attributes inside it are applied against the view model, and useKoViewModel retrieves that model from any React component in the scope. Nested scopes provide their own model. Knockout cannot take ownership of descendants rendered by React, so the structural if, ifnot, foreach, template, and with bindings are rejected; render that structure with React and useKoValue, or use KoForeach for lists. Bindings that replace an element's contents, including text, html, component, and options, require an empty host in JSX so Knockout exclusively owns the contents. Custom and overridden binding handlers must also leave React-rendered children in place during both initialization and updates; a mutation is restored and rejected. When a scope's view model is replaced, every binding root that would be cleaned is checked first. A custom or overridden binding that cannot be safely retired rejects the replacement instead of running its initializer again. useKoValue brings a Knockout value into React, for the places data-bind cannot reach — JSX interpolation, props, effect dependencies.

If a list's rows contain no data-bind, it is a plain React list: read it with useKoValue(vm.items) and call .map(...) with ordinary React keys. KoForeach only adds a per-row Knockout binding root, so it adds nothing in that case.

There are five runtime exports: KnockoutScope, useKoViewModel, useKoValue, KoForeach for lists, and useKoBind for making a particular existing element the binding root when a wrapper cannot be used. A host that cannot be discovered during React's insertion phase is rejected; this includes closed shadow roots, detached trees such as a DocumentFragment, and secondary Document objects not reachable from the page. Use KnockoutScope at those render locations. Hosts in reachable same-origin iframes are supported. The host must be an HTML element; JavaScript calls that attach the returned ref to an SVG or MathML element are rejected at runtime. TypeScript users can also import KoBindProps, the type returned by useKoBind. The documentation covers each.


Quick Start with Starter Template

TypeScript

npx degit menimani/react-ko/starter/ts my-app-ts
cd my-app-ts
npm install && npm run dev

Template source: starter/ts

JavaScript

npx degit menimani/react-ko/starter/js my-app-js
cd my-app-js
npm install && npm run dev

Template source: starter/js


Why react-ko?

Without react-ko (pure React):

<input
  value={value}
  onChange={(e) => setValue(e.target.value)}
  style={{ color }}
/>

With react-ko:

<input data-bind="value: value, style: { color: color }" />

For DOM behavior handled through data-bind, there is no need to wire React events or manage local state. Let Knockout observables do the work — even in modern React.


Development

npm install
npm run build

Enable the repository hooks once per clone:

git config core.hooksPath .githooks

The starters are npm workspaces: after the root install they run against the local library without publishing.

npm run dev --workspace=starter/ts

The documentation site is the docs/ directory, published by GitHub Pages. The autonomous improvement loop that maintains this repository lives in orchestration/; orchestration/CLAUDE.md explains how to run and resume it.


License

MIT