Context

@Ctx shares state between components through the tree — no prop drilling required. A parent defines a value, and any descendant can read it.

Providing context

Define a @Ctx property with an initial value. This component becomes the provider for any descendant with the same property name:

@Component()
class App extends BaseComponent {
  @Ctx() theme = 'dark';
  @Ctx() locale = 'en';

  view() {
    return (
      <Layout>
        <Sidebar />
        <Content />
      </Layout>
    );
  }
}

Consuming context

Descendants declare a @Ctx property with the same name. The framework walks up the component tree and finds the nearest ancestor that provides it:

@Component()
class ThemedButton extends BaseComponent {
  @Ctx() theme!: string;

  view() {
    return <button class={this.theme}>Click</button>;
  }
}

If no ancestor provides theme, the field’s initial value is used as fallback.

Transforming values

Pass a mapper function to derive a different value from the parent’s context:

@Component()
class InverseTheme extends BaseComponent {
  @Ctx((theme: string) => theme === 'dark' ? 'light' : 'dark')
  theme!: string;
}

Provider and consumer pattern

Context flows one way — down the tree. Providers can update the value, consumers are read-only:

// Provider (root) — can read and write
@Component()
class ThemeProvider extends BaseComponent {
  @Ctx() theme = 'dark';

  toggleTheme() {
    this.theme = this.theme === 'dark' ? 'light' : 'dark';
  }
}

// Consumer (descendant) — read-only
@Component()
class ThemeConsumer extends BaseComponent {
  @Ctx() theme!: string;
  // this.theme reflects the provider's value
  // assigning to this.theme has no effect
}