0
# Component Development
1
2
Core decorators and utilities for creating web components with TypeScript and JSX. Stencil provides a comprehensive decorator-based component authoring system with full TypeScript support.
3
4
## Capabilities
5
6
### Component Decorator
7
8
The main decorator for defining a web component class with configuration options.
9
10
```typescript { .api }
11
/**
12
* The @Component() decorator is used to provide metadata about the component class
13
* @param opts - Component configuration options
14
* @returns Class decorator
15
*/
16
function Component(opts: ComponentOptions): ClassDecorator;
17
18
interface ComponentOptions {
19
/** Tag name of the web component. Must contain a '-' */
20
tag: string;
21
/** Relative URL to external stylesheet file */
22
styleUrl?: string;
23
/** Array of stylesheets or mode-specific stylesheets */
24
styleUrls?: string[] | ModeStyles;
25
/** Inline CSS styles */
26
styles?: string | { [modeName: string]: any };
27
/** Use native shadow DOM encapsulation */
28
shadow?: boolean | ShadowRootOptions;
29
/** Use scoped stylesheets without native shadow DOM */
30
scoped?: boolean;
31
/** Array of relative paths to asset directories */
32
assetsDirs?: string[];
33
/** Enable form-associated component behavior */
34
formAssociated?: boolean;
35
}
36
37
interface ShadowRootOptions {
38
/** Mitigate custom element focusability issues */
39
delegatesFocus?: boolean;
40
}
41
42
interface ModeStyles {
43
[modeName: string]: string | string[];
44
}
45
```
46
47
**Usage Example:**
48
49
```typescript
50
@Component({
51
tag: 'my-button',
52
styleUrl: 'my-button.css',
53
shadow: true,
54
})
55
export class MyButton {
56
// Component implementation
57
}
58
```
59
60
### Property Decorators
61
62
Decorators for defining component properties, state, and element references.
63
64
```typescript { .api }
65
/**
66
* The @Prop() decorator defines component properties/attributes
67
* @param opts - Property configuration options
68
* @returns Property decorator
69
*/
70
function Prop(opts?: PropOptions): PropertyDecorator;
71
72
interface PropOptions {
73
/** Custom attribute name override */
74
attribute?: string | null;
75
/** Allow internal mutation of the prop */
76
mutable?: boolean;
77
/** Reflect property changes to attribute */
78
reflect?: boolean;
79
}
80
81
/**
82
* The @State() decorator manages internal component state
83
* @returns Property decorator
84
*/
85
function State(): PropertyDecorator;
86
87
/**
88
* The @Element() decorator provides reference to the host element
89
* @returns Property decorator
90
*/
91
function Element(): PropertyDecorator;
92
93
/**
94
* The @AttachInternals() decorator provides access to ElementInternals
95
* for form-associated components
96
* @returns Property decorator
97
*/
98
function AttachInternals(): PropertyDecorator;
99
```
100
101
**Usage Examples:**
102
103
```typescript
104
export class MyComponent {
105
@Prop() name: string;
106
@Prop({ reflect: true }) active: boolean;
107
@State() private count: number = 0;
108
@Element() el: HTMLElement;
109
@AttachInternals() internals: ElementInternals;
110
}
111
```
112
113
### Method Decorators
114
115
Decorators for exposing public methods and watching property changes.
116
117
```typescript { .api }
118
/**
119
* The @Method() decorator exposes methods on the public API
120
* @param opts - Method configuration options
121
* @returns Method decorator
122
*/
123
function Method(opts?: MethodOptions): MethodDecorator;
124
125
interface MethodOptions {}
126
127
/**
128
* The @Watch() decorator watches for property changes
129
* @param propName - Name of the property to watch
130
* @returns Method decorator
131
*/
132
function Watch(propName: string): MethodDecorator;
133
```
134
135
**Usage Examples:**
136
137
```typescript
138
export class MyComponent {
139
@Prop() value: string;
140
141
@Method()
142
async reset(): Promise<void> {
143
this.value = '';
144
}
145
146
@Watch('value')
147
valueChanged(newValue: string, oldValue: string) {
148
console.log('Value changed:', oldValue, '->', newValue);
149
}
150
}
151
```
152
153
### Event System
154
155
Decorators and utilities for creating and listening to custom events.
156
157
```typescript { .api }
158
/**
159
* The @Event() decorator creates custom DOM events
160
* @param opts - Event configuration options
161
* @returns Property decorator
162
*/
163
function Event(opts?: EventOptions): PropertyDecorator;
164
165
interface EventOptions {
166
/** Custom event name override */
167
eventName?: string;
168
/** Whether the event bubbles up through the DOM */
169
bubbles?: boolean;
170
/** Whether the event is cancelable */
171
cancelable?: boolean;
172
/** Whether the event can bubble across shadow DOM boundary */
173
composed?: boolean;
174
}
175
176
/**
177
* The @Listen() decorator listens to DOM events
178
* @param eventName - Name of the event to listen to
179
* @param opts - Listener configuration options
180
* @returns Method decorator
181
*/
182
function Listen(eventName: string, opts?: ListenOptions): MethodDecorator;
183
184
interface ListenOptions {
185
/** Where to attach the event listener */
186
target?: ListenTargetOptions;
187
/** Use capturing phase */
188
capture?: boolean;
189
/** Use passive event listener */
190
passive?: boolean;
191
}
192
193
type ListenTargetOptions = 'body' | 'document' | 'window';
194
195
interface EventEmitter<T = any> {
196
emit: (data?: T) => CustomEvent<T>;
197
}
198
```
199
200
**Usage Examples:**
201
202
```typescript
203
export class MyComponent {
204
@Event() myCustomEvent: EventEmitter<string>;
205
@Event({ bubbles: false }) myPrivateEvent: EventEmitter<number>;
206
207
@Listen('click')
208
handleClick(event: MouseEvent) {
209
this.myCustomEvent.emit('Button clicked!');
210
}
211
212
@Listen('resize', { target: 'window' })
213
handleResize(event: Event) {
214
console.log('Window resized');
215
}
216
}
217
```
218
219
### JSX and Rendering
220
221
Functions and utilities for JSX templating and virtual DOM creation.
222
223
```typescript { .api }
224
/**
225
* JSX pragma function for creating virtual DOM nodes
226
* @param sel - Element selector or component
227
* @param data - Element attributes and properties
228
* @param children - Child elements
229
* @returns Virtual DOM node
230
*/
231
function h(sel: any): VNode;
232
function h(sel: Node, data: VNodeData | null): VNode;
233
function h(sel: any, data: VNodeData | null): VNode;
234
function h(sel: any, text: string): VNode;
235
function h(sel: any, children: Array<VNode | undefined | null>): VNode;
236
function h(sel: any, data: VNodeData | null, text: string): VNode;
237
function h(sel: any, data: VNodeData | null, children: Array<VNode | undefined | null>): VNode;
238
function h(sel: any, data: VNodeData | null, children: VNode): VNode;
239
240
/**
241
* Host functional component for setting attributes on the host element
242
*/
243
declare const Host: FunctionalComponent<HostAttributes>;
244
245
interface HostAttributes {
246
class?: string | { [className: string]: boolean };
247
style?: { [key: string]: string | undefined };
248
ref?: (el: HTMLElement | null) => void;
249
[prop: string]: any;
250
}
251
252
/**
253
* Fragment functional component for multiple children without wrapper
254
*/
255
declare const Fragment: FunctionalComponent<{}>;
256
257
/**
258
* Render virtual DOM tree to a container element
259
* @param vnode - Virtual DOM tree to render
260
* @param container - Container element to render into
261
*/
262
function render(vnode: VNode, container: Element): void;
263
```
264
265
**Usage Examples:**
266
267
```typescript
268
export class MyComponent {
269
@Prop() items: string[];
270
271
render() {
272
return (
273
<Host class="my-component">
274
<div class="header">
275
<h1>My Component</h1>
276
</div>
277
<div class="content">
278
{this.items.map(item => (
279
<div class="item" key={item}>
280
{item}
281
</div>
282
))}
283
</div>
284
</Host>
285
);
286
}
287
}
288
289
// Using Fragment
290
render() {
291
return (
292
<Fragment>
293
<div>First child</div>
294
<div>Second child</div>
295
</Fragment>
296
);
297
}
298
```
299
300
### Lifecycle Hooks
301
302
Component lifecycle interfaces for handling component state changes.
303
304
```typescript { .api }
305
interface ComponentWillLoad {
306
/**
307
* Called once before the component's first render
308
*/
309
componentWillLoad(): Promise<void> | void;
310
}
311
312
interface ComponentDidLoad {
313
/**
314
* Called once after the component's first render
315
*/
316
componentDidLoad(): void;
317
}
318
319
interface ComponentWillUpdate {
320
/**
321
* Called before each render (except the first)
322
*/
323
componentWillUpdate(): Promise<void> | void;
324
}
325
326
interface ComponentDidUpdate {
327
/**
328
* Called after each render (except the first)
329
*/
330
componentDidUpdate(): void;
331
}
332
333
interface ComponentInterface {
334
connectedCallback?(): void;
335
disconnectedCallback?(): void;
336
componentWillLoad?(): Promise<void> | void;
337
componentDidLoad?(): void;
338
componentWillUpdate?(): Promise<void> | void;
339
componentDidUpdate?(): void;
340
componentWillRender?(): Promise<void> | void;
341
componentDidRender?(): void;
342
componentShouldUpdate?(newVal: any, oldVal: any, propName: string): boolean | void;
343
render?(): any;
344
}
345
```
346
347
**Usage Example:**
348
349
```typescript
350
export class MyComponent implements ComponentInterface {
351
@State() private data: any[] = [];
352
353
async componentWillLoad() {
354
// Load data before first render
355
this.data = await fetchData();
356
}
357
358
componentDidLoad() {
359
// Component is ready, set up event listeners
360
console.log('Component loaded');
361
}
362
363
componentShouldUpdate(newVal: any, oldVal: any, propName: string): boolean {
364
// Control when component should update
365
return newVal !== oldVal;
366
}
367
368
render() {
369
return <div>{this.data.length} items loaded</div>;
370
}
371
}
372
```
373
374
### Functional Components
375
376
Support for functional components with utilities for working with children.
377
378
```typescript { .api }
379
interface FunctionalComponent<T = {}> {
380
(props: T, children: VNode[], utils: FunctionalUtilities): VNode | VNode[];
381
}
382
383
interface FunctionalUtilities {
384
/**
385
* Iterate over children with a callback
386
*/
387
forEach: (children: VNode[], cb: (vnode: ChildNode, index: number, array: ChildNode[]) => void) => void;
388
/**
389
* Transform children and return new array
390
*/
391
map: (children: VNode[], cb: (vnode: ChildNode, index: number, array: ChildNode[]) => ChildNode) => VNode[];
392
}
393
394
interface ChildNode {
395
vtag?: string | number | Function;
396
vkey?: string | number;
397
vtext?: string;
398
vchildren?: VNode[];
399
vattrs?: any;
400
vname?: string;
401
}
402
```
403
404
**Usage Example:**
405
406
```typescript
407
export const AddClass: FunctionalComponent = (_, children, utils) => (
408
utils.map(children, child => ({
409
...child,
410
vattrs: {
411
...child.vattrs,
412
class: `${child.vattrs.class} add-class`
413
}
414
}))
415
);
416
417
// Usage in JSX
418
render() {
419
return (
420
<AddClass>
421
<div>This will have 'add-class' added</div>
422
</AddClass>
423
);
424
}
425
```