Components

EmberKit components are plain functions that return JSX elements. They follow the same mental model as React but with zero runtime overhead by default.

Defining a Component

function Button({ children, variant = 'primary' }: { children: unknown; variant?: string }) {
  return (
    <button className={`btn btn-${variant}`}>
      {children}
    </button>
  );
}

Components receive a single props object and return JSX. There are no class components, no lifecycle methods, and no this binding.

Using Components

function App() {
  return (
    <div>
      <Button>Click me</Button>
      <Button variant="secondary">Cancel</Button>
    </div>
  );
}

Children

Components can accept children to act as wrappers:

function Card({ children, title }: { children: unknown; title: string }) {
  return (
    <div className="card">
      <h3 className="card-title">{title}</h3>
      <div className="card-body">{children}</div>
    </div>
  );
}

Conditional Rendering

Use JavaScript expressions for conditional output:

function Status({ online }: { online: boolean }) {
  return (
    <div>
      {online ? <span className="badge-green">Online</span> : <span className="badge-red">Offline</span>}
    </div>
  );
}

Lists

Use map to render lists with key props:

function TodoList({ items }: { items: string[] }) {
  return (
    <ul>
      {items.map((item) => (
        <li key={item}>{item}</li>
      ))}
    </ul>
  );
}

Static vs Interactive

function Title() {
  return <h1>Hello</h1>;
}

function Counter() {
  const [count, setCount] = createSignal(0);
  return (
    <div>
      <button type="button" onClick={() => setCount((c) => c + 1)}>+</button>
      <span data-ek-bind={count}>{count()}</span>
    </div>
  );
}

Details: Hydration. Signal props on components: Signals.

Props Interface

Define prop types with TypeScript interfaces:

interface ButtonProps {
  children: unknown;
  variant?: 'primary' | 'secondary' | 'ghost';
  size?: 'sm' | 'md' | 'lg';
  disabled?: boolean;
  onClick?: () => void;
}

function Button({ children, variant = 'primary', size = 'md', disabled, onClick }: ButtonProps) {
  return (
    <button
      className={`btn btn-${variant} btn-${size}`}
      disabled={disabled}
      onClick={onClick}
    >
      {children}
    </button>
  );
}

Next Steps