Stimulus Decorators is a TypeScript library that extends the Stimulus framework with TypeScript decorators to give you improved IntelliSense and type safety of automatically generated Stimulus controller properties.
If you use Yarn package manager.
yarn add @vytant/stimulus-decorators
If you use npm package manager.
npm install --save @vytant/stimulus-decorators
There are several decorators:
@Target
decoratorExplicitly define target properties with types using the @Target
decorator, and it will automatically add them to the static targets
array for your Stimulus controller.
// hello_controller.ts
import { Controller } from '@hotwired/stimulus';
import { Target, TypedController } from '@vytant/stimulus-decorators';
@TypedController
export default class extends Controller {
@Target outputTarget!: HTMLElement;
@Target nameTarget!: HTMLInputElement;
greet() {
this.outputTarget.textContent = `Hello, ${this.nameTarget.value}!`;
}
}
Equivalent to:
// hello_controller.js
import { Controller } from '@hotwired/stimulus';
export default class extends Controller {
static targets = ['name', 'output'];
greet() {
this.outputTarget.textContent = `Hello, ${this.nameTarget.value}!`;
}
}
@Targets
decoratorTo get an array of all matching targets in scope, use the @Targets
decorator.
// slider_controller.ts
import { Controller } from '@hotwired/stimulus';
import { Targets, TypedController } from '@vytant/stimulus-decorators';
@TypedController
export default class extends Controller {
@Targets slideTargets!: HTMLElement[];
connect() {
this.slideTargets.forEach((element, index) => {
/* … */
});
}
}
Equivalent to:
// slider_controller.js
import { Controller } from '@hotwired/stimulus';
export default class extends Controller {
static targets = ['slide'];
connect() {
this.slideTargets.forEach((element, index) => {
/* … */
});
}
}
@Value
decoratorExplicitly define value properties with types and default values using the @Value
decorator, and it will automatically add them to the static values
object for your Stimulus controller.
// loader_controller.ts
import { Controller } from '@hotwired/stimulus';
import { Value, TypedController } from '@vytant/stimulus-decorators';
@TypedController
export default class extends Controller {
@Value(String) urlValue!: string;
@Value(String) methodValue: string = 'GET';
connect() {
fetch(this.urlValue, { method: this.methodValue }).then(/* … */);
}
}
Equivalent to:
// loader_controller.js
import { Controller } from '@hotwired/stimulus';
export default class extends Controller {
static values = {
url: String,
method: { type: String, default: 'GET' },
};
connect() {
fetch(this.urlValue, { method: this.methodValue }).then(/* … */);
}
}
type
of each value from its type definition, you must use reflect-metadata."emitDecoratorMetadata": true
in your tsconfig.json
.reflect-metadata
before importing @vytant/stimulus-decorators
(importing reflect-metadata
is needed just once).// loader_controller.ts
import 'reflect-metadata';
import { Controller } from '@hotwired/stimulus';
import { Value, TypedController } from '@vytant/stimulus-decorators';
@TypedController
export default class extends Controller {
@Value urlValue!: string;
@Value methodValue: string = 'GET';
connect() {
fetch(this.urlValue, { method: this.methodValue }).then(/* … */);
}
}
@Class
decoratorExplicitly define CSS class properties with types using the @Class
decorator, and it will automatically add them to the static classes
array for your Stimulus controller.
// search_controller.ts
import { Controller } from '@hotwired/stimulus';
import { Class, TypedController } from '@vytant/stimulus-decorators';
@TypedController
export default class extends Controller {
@Class loadingClass!: string;
loadResults() {
this.element.classList.add(this.loadingClass);
fetch(/* … */);
}
}
Equivalent to:
// search_controller.js
import { Controller } from '@hotwired/stimulus';
export default class extends Controller {
static classes = ['loading'];
loadResults() {
this.element.classList.add(this.loadingClass);
fetch(/* … */);
}
}
@Classes
decoratorTo get an array of classes in the corresponding CSS class attribute, use the @Classes
decorator.
// search_controller.ts
import { Controller } from '@hotwired/stimulus';
import { Classes, TypedController } from '@vytant/stimulus-decorators';
@TypedController
export default class extends Controller {
@Classes loadingClasses!: string[];
loadResults() {
this.element.classList.add(...this.loadingClasses);
fetch(/* … */);
}
}
Equivalent to:
// search_controller.js
import { Controller } from '@hotwired/stimulus';
export default class extends Controller {
static classes = ['loading'];
loadResults() {
this.element.classList.add(...this.loadingClasses);
fetch(/* … */);
}
}
@TypedController
decoratorIt is required to use the @TypedController
decorator on every Stimulus controller where you use @Target
, @Targets
, or @Value
decorators.
// controller.ts
import { Controller } from '@hotwired/stimulus';
import { TypedController } from '@vytant/stimulus-decorators';
@TypedController
export default class extends Controller {
/* … */
}
The project is MIT licensed.