--- title: "@controller" description: "Register a RadiantController class for data-controller discovery." group: Decorators order: 6 --- # @controller `@controller(identifier)` registers a `RadiantController` class for `data-controller` discovery. It is equivalent to calling `registerController(identifier, ControllerClass)` directly. If controller runtimes are already running, newly registered identifiers are reconciled against the live DOM immediately. ## Example ```ts import { RadiantController, controller } from '@ecopages/radiant'; import { startControllers } from '@ecopages/radiant/controller-registry'; @controller('search') class SearchController extends RadiantController { connect() { super.connect(); } } startControllers(document); ``` ```html
``` ## Identifier Rules - the identifier must be unique across the page runtime - re-registering the same constructor is a no-op - registering a different constructor for an existing identifier keeps the original controller by default That default prevents an accidental second registration from mutating already-connected controller instances. When tooling does need mutation, use the explicit runtime APIs instead of changing the default decorator contract. ## Tooling Hooks The registry also exposes explicit mutation hooks. Prefer the focused `@ecopages/radiant/controller-registry` subpath when a module only needs registry APIs: - `replaceController(...)` - `enableControllerReplacementForHmr()` Use those APIs for HMR or code-generation workflows that intentionally replace a controller class after the first registration. ## Related Runtime API The registry also exposes an explicit runtime surface through the focused `@ecopages/radiant/controller-registry` subpath, and also re-exports it from `@ecopages/radiant` for convenience: - `registerController(...)` - `replaceController(...)` - `enableControllerReplacementForHmr()` - `startControllers(...)` - `stopControllers()` - `CONTROLLER_ATTRIBUTE` - `ControllerRegistryRuntime` Prefer the focused subpath for setup modules and tooling hooks. Reach for the root entry only when that module is already importing broader controller APIs and the convenience matters more than the narrower import boundary. ## See Also - [RadiantController](/docs/components/radiant-controller) - [Controller Tooling & HMR](/docs/tools/controller-tooling-hmr) - [@attr](/docs/decorators/attr)