Preact UI toolkit.
10x smaller than you think.

Kinu: the Japanese word for silk. An ultra-thin layer of styling and ergonomics over native HTML. Zero dependencies, zero runtime overhead, zero wrapper divs.

new-post.tsx28 lines
import {Field, Input, Select, Switch, Label, Button, toast} from 'kinu';

export function NewPost() {
  return (
    <form onSubmit={(e) => {
      e.preventDefault();
      toast.show('Post published', {icon: '✓'});
    }}>
      <Field>
        <Field.Label>Title</Field.Label>
        <Input name="title" placeholder="On silk and software" required />
      </Field>
      <Field>
        <Field.Label>Audience</Field.Label>
        <Select name="audience" defaultValue="subscribers">
          <option value="subscribers">Subscribers</option>
          <option value="team">Team only</option>
          <option value="public">Public</option>
        </Select>
      </Field>
      <div class="row">
        <Switch id="notify" name="notify" defaultChecked />
        <Label htmlFor="notify">Email subscribers</Label>
      </div>
      <Button type="submit">Publish →</Button>
    </form>
  );
}
previewLive

The platform
does the work.

Other toolkits put state, positioning, and focus management in JavaScript. Kinu pushes them down into commandfor, native <dialog>, anchor positioning, and the form-associated elements your browser already ships. Less code shipped. Less code called. Same JSX in, same pixels out.

Same JSX in. Same pixels out. The whole middle of the diagram lives in your browser already.

Built with Kinu.

Eight real product surfaces, composed from the components in this toolkit. The whole grid runs on the same ~11 kB you'd ship.

Tasks
JD

Q4 launches

2/4 done
Media Player

Summer Breeze

DJ Sunwave · Golden Hour

0:584:18
AI Composer
✦
Hi — I'm a placeholder model running inside this card. Try asking about kinu's bundle size, or just say hello.
Anthropic
OpenAI
Google
Activity
JMASKM+4
Live
  • JM

    Jason merged pull/124

    2m
  • AS

    Alex is reviewing pull/126

    7m
  • KM

    Karen opened issue #2031

    14m
  • TR

    Toshi is away

    1h
Command Palette
Pages
Actions
Recent
Trip Booking
4 nights · $640
Inbox2
JM
Jason Miller
2m

Build is green

Hey — CI is green and the bundle is at 11.2 kB. The changeset touched theme tokens, so I tagged you. Want to look at it before I cut a release? No rush.

Settings
JM

We sent a code to jason@kinu.sh.

Resend in 0:42

JSX in, native HTML out.

The Dialog you write on the left renders as the markup on the right. No portals, no state hooks — just commandfor, a native <dialog>, and the form-associated elements you already know.

You write
// edit-profile.tsx
import {Dialog, Field, Input, Button} from 'kinu';

export function EditProfile() {
  return (
    <Dialog>
      <Dialog.Trigger>
        <Button>Edit profile</Button>
      </Dialog.Trigger>
      <Dialog.Content>
        <Field>
          <Field.Label>Display name</Field.Label>
          <Input defaultValue="Jason" required />
        </Field>
        <Dialog.Close>
          <Button>Save</Button>
        </Dialog.Close>
      </Dialog.Content>
    </Dialog>
  );
}
The browser sees
<!-- ESC closes. Click-outside closes. Focus is trapped. Free. -->
<button commandfor="d-1" command="show-modal">
  Edit profile
</button>

<dialog id="d-1">
  <div k="field">
    <label>Display name</label>
    <input k="input" value="Jason" required />
  </div>
  <button commandfor="d-1" command="close">Save</button>
</dialog>

Ship less. Do more.

60+ components. ~5kB of JS, ~6kB of CSS. No dependencies, no surprises.