npm install @stencil/core
npm init stencil
@Prop()
import { Component, h, Prop } from '@stencil/core';
@Component({
tag: 'say-hello'
})
export class SayHello {
@Prop() name: string;
render() {
return <p>Hello, World! I'm {this.name}.</p>;
}
}
<say-hello name="Carla"></say-hello>
<say-hello name="Carla">
<p>Hello, World! I'm Carla.</p>
</say-hello>
@State()
import { Component, h, State } from '@stencil/core';
@Component({
tag: 'click-counter'
})
export class ClickCounter {
//...
//...
@State() count = 0;
private incrementCount() {
this.count++;
}
//...
//...
render() {
return (
<div>
<p>{this.count}</p>
<button
type="button"
onClick={() => this.incrementCount()}
>Plus 1</button>
</div>
);
}
}
@Watch()
import { Component, h, Prop, Watch } from '@stencil/core';
@Component({
tag: 'say-hello'
})
export class SayHello {
@Prop() name: string;
@Watch('name')
updateName(newValue, oldValue) {
// Fire name-related event, perhaps...
}
//...
//...
render() {
return <p>Hello, World! I'm {this.name}.</p>;
}
}
@Event()
@Listen()
import { Component, Event, EventEmitter, h } from '@stencil/core';
@Component({
tag: 'modal-trigger'
})
export class ModalTrigger {
// ..
//...
@Event() openModal!: EventEmitter;
private triggerClick() {
this.openModal.emit();
}
//...
//...
render() {
return (
<button onClick={() => this.triggerClick()}>
<slot />
</button>
);
}
}
import { Component, h, Listen, State } from '@stencil/core';
@Component({
tag: 'modal-window'
})
export class ModalWindow {
// ..
//...
@State() isOpen = false;
@Listen('openModal')
openModalWindow() {
this.isOpen = true;
}
//...
//...
render() {
const modalClasses = {
modal: true,
'modal--open': this.isOpen
};
return (
<section class={modalClasses}>
<slot />
</section>
);
}
}
<modal-trigger>
Log In
</modal-trigger>
<modal-window>
<form></form>
</modal-window>
connectedCallback()
Every time it’s connected to DOM, before componentWillLoad()
disconnectedCallback()
Every time it’s disconnected from DOM
componentWillLoad()
Runs 1x after component 1st connects to DOM
componentDidLoad()
Called once after fully loaded & 1st render()
componentWillRender()
Before every render()
componentDidRender()
After every render()
componentWillUpdate()
When @Prop()
or @State()
change (not 1st render()
)
componentDidUpdate()
After update render()
(but not 1st render()
)
Completely scoped styles:
Outer styles can’t leak in;
inner styles can’t leak out.
:host
, :host()
:host-context()
::slotted()
::part()
*:host {
display: block;
}
:host(.is-blue) {
color: blue;
}
:host([aria-hidden="true"]) {
opacity: 0;
}
:host-context(article) {
width: 50%;
}
:host-context(aside) {
width: 100%;
}
::slotted(svg) {
margin-right: 8px;
width: 22px;
}
::slotted(svg *) {
fill: var(--button-fg, #FFF);
}
render() {
return (<div>
<button part="trigger">Click Me</button>
</div>);
}
/* Outer CSS allowed through the Shadow DOM */
custom-element::part(trigger) {
color: dodgerblue;
}
* Implemented in Firefox/Chrome, not in Spec
CSS Custom Properties are the only things allowed to affect Shadow DOM elements.
export class CustomButton {
render() {
return (
<button class="button">
<slot />
</button>
);
}
}
/* Attached to Shadow DOM */
.button {
color: var(--button-fg, #FFF);
background: var(--button-bg, #1976D2);
}
.button:hover {
color: var(--button-fg-active, #FFF);
background: var(--button-bg-active, #1565C0);
}
/* Outer CSS: inherited by Shadow DOM */
.button-container--red {
--button-bg: #D32F2F;
--button-bg-active: #B71C1C;
}
npm run build
Get /dist/*
onto your server
or into your site build process.
Instructions in Stencil Docs:
jdsteinbach