Skip to content

Event Handlers

Event handlers in Kaori use the on* attribute pattern, similar to React.

Basic Event Handling

tsx
function Button() {
  function handleClick(event: MouseEvent) {
    console.log('Clicked!', event);
  }

  return () => <button onClick={handleClick}>Click me</button>;
}

This is equivalent to calling addEventListener('click', clickHandler) on the button element.

tsx
// compiler output
import { html } from 'kaori.js';

function Button() {
  function handleClick(event: MouseEvent) {
    console.log('Clicked!', event);
  }

  return () => html`<button @click=${handleClick}>Click me</button>`;
}

Inline Handlers

tsx
function Counter() {
  const count = signal(0);

  return () => (
    <button onClick={() => count.value++}>Count: {count.value}</button>
  );
}

Common Events

tsx
function Form() {
  return () => (
    <div>
      <button onClick={e => console.log('click')}>Click</button>
      <input onChange={e => console.log('change')} />
      <input onInput={e => console.log('input')} />
      <form onSubmit={e => e.preventDefault()}>Submit</form>
      <div onMouseEnter={() => {}} onMouseLeave={() => {}}>
        Hover
      </div>
      <input onFocus={() => {}} onBlur={() => {}} />
      <input onKeyDown={e => {}} onKeyUp={e => {}} />
    </div>
  );
}

Event Options

Pass an object with handleEvent method and options:

tsx
<button
  onClick={{
    handleEvent: e => console.log('clicked'),
    capture: true,
    passive: true,
    once: true,
  }}
>
  Click me
</button>

Preventing Default

tsx
function Link() {
  function handleClick(e: MouseEvent) {
    e.preventDefault();
    console.log('Link clicked but not navigating');
  }

  return () => (
    <a href="/page" onClick={handleClick}>
      Click
    </a>
  );
}

Event Delegation

Events automatically bubble up:

tsx
function List() {
  function handleListClick(e: MouseEvent) {
    const target = e.target as HTMLElement;
    if (target.tagName === 'LI') {
      console.log('Item clicked:', target.textContent);
    }
  }

  return () => (
    <ul onClick={handleListClick}>
      <li>Item 1</li>
      <li>Item 2</li>
      <li>Item 3</li>
    </ul>
  );
}

Best Practices

tsx
// ✅ Extract handlers for reusability
function handleClick() {}

// ✅ Use event types
function handleChange(e: ChangeEvent) {}

// ✅ Prevent default when needed
function handleSubmit(e: Event) {
  e.preventDefault();
}

// ❌ Don't create functions in render
return () => {
  // Creates new function each render
  const handler = () => {};
  return <button onClick={handler}>Bad</button>;
};

Made with 💖 by golok