Component metadata

@Component is where a view declares its slice of the world: scoped providers, module imports for standalone-style composition, and the controllers its subtree shares.

The three fields

@Component({
  providers:   [DraftStore],            // this view's own scope only
  controllers: [EditorController],      // shared with the whole subtree
  imports:     [SharedModule],          // pull a module's providers in scope
})
export class EditorView extends View { /* … */ }
FieldEffect
providersComponent-level providers, Angular-style: one instance per mounted view, visible to the view and its descendants. Overrides a module provider of the same token for this subtree.
controllersRegistered in the view's injector — parent and nested child views injecting the same controller share one instance. See Controllers.
importsStandalone-component imports: the module's providers and declared components join this view's scope, no module needed. See below.

Standalone views: imports without a module

A view that isn't declared by any module can still pull a module's providers into its own injector — Angular's standalone: true + imports pattern:

shared.module.ts
@Module({ providers: [ThemeService] })
export class SharedModule {}

// hello.view.tsx — declared in NO module, still gets ThemeService:
@Component({ imports: [SharedModule] })
export class HelloView extends View {
  private theme = inject(ThemeService); // resolved from the imported module
  render() { /* … */ }
}

The imported module's declared components are also mountable inside this view's subtree — the ownership check treats the view's injector as part of that module's closure.

Choosing a scope

NeedDeclare on
App-wide singleton@Injectable({ providedIn: 'root' }) or root module providers
Feature-wide state@Module({ providers })
Per-screen state reset on navigation@Component({ providers })
Shared form/interaction controller@Component({ controllers })
Module-less view needing module services@Component({ imports })