Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
The State of Web Components
Search
Shogo Sensui
September 24, 2017
Technology
9
9.2k
The State of Web Components
2017年9月24日に開催された HTML5 Conference 2017 の「The State of Web Components」のセッション資料です。
Shogo Sensui
September 24, 2017
Tweet
Share
More Decks by Shogo Sensui
See All by Shogo Sensui
三年間の関わりから見る PR TIMES エンジニアリングの変化 / Transition of PRTimes Engineering
1000ch
0
2.5k
EU のデジタル市場法と Apple / DMA and Apple
1000ch
0
160
Web Share API
1000ch
0
180
2023 年の Web 開発のベースライン / Web Development Baseline 2023
1000ch
0
90
開発生産性と組織 / Productivity and Organization
1000ch
0
1.2k
なぜ私達は働くのか / Why We Work?
1000ch
0
120
新しいメルカリ Web とそのパフォーマンス / The New Mercari Web and its performance
1000ch
0
140
Web Standards Interop 2022
1000ch
0
370
パフォーマンスを高める CSS / Performance Optimized CSS
1000ch
1
870
Other Decks in Technology
See All in Technology
製造業ドメインにおける LLMプロダクト構築: 複雑な文脈へのアプローチ
caddi_eng
1
550
マルチロールEMが実践する「組織のレジリエンス」を高めるための組織構造と人材配置戦略
coconala_engineer
3
680
Ultra Ethernet (UEC) v1.0 仕様概説
markunet
3
250
OpenClawで回す組織運営
jacopen
3
670
Claude Codeが爆速進化してプラグイン追従がつらいので半自動化した話 ver.2
rfdnxbro
0
480
スクリプトの先へ!AIエージェントと組み合わせる モバイルE2Eテスト
error96num
0
140
白金鉱業Meetup_Vol.22_Orbital Senseを支える衛星画像のマルチモーダルエンベディングと地理空間のあいまい検索技術
brainpadpr
2
280
SRE NEXT 2026 CfP レビュアーが語る聞きたくなるプロポーザルとは?
yutakawasaki0911
0
200
JAWS DAYS 2026 楽しく学ぼう!ストレージ 入門
yoshiki0705
2
130
Kubernetesにおける推論基盤
ry
1
210
プロジェクトマネジメントをチームに宿す -ゼロからはじめるチームプロジェクトマネジメントは活動1年未満のチームの教科書です- / 20260304 Shigeki Morizane
shift_evolve
PRO
1
150
[JAWSDAYS2026]Who is responsible for IAM
mizukibbb
0
310
Featured
See All Featured
Darren the Foodie - Storyboard
khoart
PRO
3
2.8k
The untapped power of vector embeddings
frankvandijk
2
1.6k
Rebuilding a faster, lazier Slack
samanthasiow
85
9.4k
Building Flexible Design Systems
yeseniaperezcruz
330
40k
Money Talks: Using Revenue to Get Sh*t Done
nikkihalliwell
0
180
Imperfection Machines: The Place of Print at Facebook
scottboms
269
14k
Large-scale JavaScript Application Architecture
addyosmani
515
110k
Become a Pro
speakerdeck
PRO
31
5.8k
First, design no harm
axbom
PRO
2
1.1k
How to build an LLM SEO readiness audit: a practical framework
nmsamuel
1
670
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
35
3.4k
Learning to Love Humans: Emotional Interface Design
aarron
275
41k
Transcript
)5.-$POGFSFODF 4IPHP4FOTVJBLB!DI 5IF4UBUFPG8FC$PNQPOFOUT
!DI
‣ 4IPHP4FOTVJ ‣ ؎ٝة٦طحزדכDIדׅ ‣ $ZCFS"HFOU *OD ‣ 8FC*OJUJBUJWF$FOUFS ‣
4PGUXBSF&OHJOFFS ‣ 8FC䪮遭Ⰻ菙ָ㥨ֹדׅ ‣ 044崞⹛׃גתׅ
馄鸞劤ָ⳿תׅ 涪㡰✮㹀
8IZ8FC$PNQPOFOUT
)5.- $44 8FC涪罏
8FCחֶֽ鿇ㅷךꨇ׃ׁ ‣ )5.-ה$44חأ؝٦فָ㶷㖈׃זְ ‣ 铣鴥$44ך䕦갟眔㔲ָ鎘濼זְ ‣ せ瑞ָ遼瑱׃זְ״ֲծ䌢ח䠐陎ׅ䗳銲ָ֮ ‣ ⡲鿇ㅷⱄⵃ欽׃חְֻ ‣
)5.- $44 +BWB4DSJQUתה➬穈ָזְ ‣ תה鿇ㅷꂁ䋒ׅؒ؝ءأذيָזַ
نةٝ⡲חכ˘ GBODZCVUUPO
<button> fancy button </button> button { background: #0086b3; color: white;
padding: 1em; border-radius: 0.5em; border: none; } )5.-ה$44剅ֽל0,
GBODZCVUUPO
GBODZCVUUPO GBODZCVUUPO
<button class="a"> fancy button </button> <button class="b"> fancy button </button>
button { color: white; padding: 1em; border-radius: 0.5em; border: none; } button.a { background: #0086b3; } button.b { background: #008080; }
GBODZCVUUPO GBODZCVUUPO
GBODZCVUUPO GBODZCVUUPO GBODZCVUUPO
GBODZCVUUPO GBODZCVUUPO GBODZCVUUPO PWBM TRVBSF
fancy button </button> <button class="b"> fancy button </button> <button class="c">
fancy button </button> <button class="oval"> oval </button> <button class="square"> border-radius: 0.5em; border: none; } button.a { background: #0086b3; } button.b { background: #008080; } button.oval { ... }
GBODZCVUUPO GBODZCVUUPO GBODZCVUUPO PWBM TRVBSF
<fancy-button color="a"> fancy button </fancy-button> <fancy-button color="b"> fancy button </fancy-button>
<fancy-button color="c"> fancy button </fancy-button> <oval-button>oval</oval-button> <square-button>square</square-button>
4IBEPX%0. $VTUPN&MFNFOUT 5FNQMBUFT )5.-*NQPSUT ˟׳התד
˟䎃猧植㖈 4IBEPX%0. $VTUPN&MFNFOUT 5FNQMBUFT &4.PEVMFT
4IBEPX%0.
4IBEPX%0.הכ ‣ )5.-ծ$44ծ+BWB4DSJQUך䕦갟眔㔲ꣲ㹀ׅ ‣ مأزהז銲稆חTIBEPX3PPU欰װ׃ծך⚥ד饯ֿֿה4IBEPX %0.ⰻח殅 ‣ 4IBEPX%0.㢩鿇ַך䕦갟ꣲ㹀ׅ ‣ TIBEPX3PPUפך،ؙإأꣲ㹀涸ח׃ծ䮶莸ְ䬐⥂ׅ
‣ TIBEPX3PPUפ،ؙإأדֹPQFOٌ٦سהծ黪倖ׅDMPTFEٌ٦سָ֮
const button = document.querySelector('button'); const shadowRoot = button.attachShadow({ mode: 'open'
// or 'close' }); // readonly property console.log(button.shadowRoot); 4IBEPX%0.ך欰װ׃倯
GBODZCVUUPO ⢽ִלְֲֲֿنةٝ
<button> fancy button </button> ֲֿ剅ֽءٝفٕ˘ <style> button { background: #0086b3;
color: white; padding: 1em; border-radius: 0.5em; border: none; }ɹ </style>
<button> #shadow-root fancy button </button> <style> button { background: #0086b3;
color: white; padding: 1em; border-radius: 0.5em; border: none; } </style> <button> <slot></slot> </button>
<button> #shadow-root fancy button </button> <style> button { background: #0086b3;
color: white; padding: 1em; border-radius: 0.5em; border: none; }ɹ </style> <button> <slot></slot> </button>
<button> #shadow-root fancy button </button> <style> button { background: #0086b3;
color: white; padding: 1em; border-radius: 0.5em; border: none; } </style> <button> <slot></slot> </button> 4DPQFE
$VTUPN&MFNFOUT
$VTUPN&MFNFOUTהכ ‣ 杝荈ך)5.-銲稆㹑鎉ׅ ‣ )5.-ד㹑鎉涸חⵃ欽דֹ ‣ %0."1*鸐ׄגㄏ⟀涸חⵃ欽דֹ ‣ ⟣䠐ך䮶莸ְ㹀纏ׅ ‣
㹀纏ׁٓ؎ؿ؟؎ؙٕؿحؙׅ
class FancyButton extends HTMLElement { constructor() { ... } connectedCallback()
{ ... } disconnectedCallback() { ... } attributeChangedCallback() { ... } adoptedCallback() { ... } } ؕأةي銲稆ٓ؎ؿ؟؎ؙٕ
䖞勻ך8FC鿇ㅷךⱄⵃ欽 ‣ 鿇ㅷ圓䧭ׅ)5.-鎸鶢ׅ ‣ $44ח״أة؎ؚٔٝ黝欽ׅ ‣ $44ؿ؋؎ٕٗ٦سׅծTUZMF銲稆剅ֻծFUD ‣ +BWB4DSJQUח״䮶莸ְ黝欽ׅ ‣
+BWB4DSJQUؿ؋؎ٕٗ٦سׅծTDSJQU銲稆剅ֻծFUD
GBODZCVUUPO نةٝ⢪ְְ˘
.fancy { background: #0086b3; color: white; padding: 1em; border-radius: 0.5em;
border: none; } CVUUPODTT
CVUUPOKT document .querySelector('.fancy') .addEventListener('click', () => { //... });
<button class="fancy"> fancy button </button> JOEFYIUNM
<link rel="stylesheet" href="button.css"> ... <button class="fancy"> fancy button </button> ...
<script src="button.js"></script> 穈さׇג⢪ֲ
None
class FancyButton extends HTMLElement { connectedCallback() { this.innerHTML = `
<style>button { … }</style> <button>fancy button</button> `; } } customElements .define('fancy-button', FancyButton);
<fancy-button> fancy button </fancy-button> GBODZCVUUPO GBODZCVUUPO⢪ִ
<fancy-button> <style> button { background: #0086b3; color: white; padding: 1em;
border-radius: 0.5em; border: none; } </style> <button> fancy button </button> </fancy-button> /PUTDPQFE
4IBEPX%0. $VTUPN&MFNFOUT
class FancyButton extends HTMLElement { connectedCallback() { this.innerHTML = `
<style>button { … }</style> <button>fancy button</button> `; } } customElements .define('fancy-button', FancyButton);
class FancyButton extends HTMLElement { connectedCallback() { this.shadowRoot.innerHTML = `
<style>button { … }</style> <button><slot></slot></button> `; } } customElements .define('fancy-button', FancyButton);
<fancy-button> <style> button { background: #0086b3; color: white; padding: 1em;
border-radius: 0.5em; border: none; } </style> <button> fancy button </button> </fancy-button>
<fancy-button> #shadow-root <style> button { background: #0086b3; color: white; padding:
1em; border-radius: 0.5em; border: none; } </style> <button> <slot></slot> </button> fancy button </fancy-button> 4DPQFE
5FNQMBUFT
5FNQMBUFTהכ ‣ ꬊ崞䚍ז)5.-銲稆㹑鎉ׅ ‣ ذٝفٖ٦زה׃ג)5.-銲稆䪔ִ ‣ 䖞勻ךعحؙ涸ז،فٗ٦ثׇ׆ח幥
<div style="display:none;"> <p>This is an image</p> <img src="foo.jpg" alt=""> </div>
4FOEBSFRVFTU
<script type="text/template"> <p>This is an image</p> <img src="foo.jpg" alt=""> </script>
&WBMXJUIJOOFS)5.-
<template> <p>This is an image</p> <img src="foo.jpg" alt=""> </template> *OFSU✨
4IBEPX%0. $VTUPN&MFNFOUT 5FNQMBUFT
class FancyButton extends HTMLElement { connectedCallback() { this.shadowRoot.innerHTML = `
<style>button { … }</style> <button><slot></slot></button> `; } } customElements .define('fancy-button', FancyButton);
<template> <style>button { … }</style> <button><slot></slot></button> </template> <script> class FancyButton
extends HTMLElement { // ... } customElements .define('fancy-button', FancyButton); </script>
<link rel="import" href="fancy-button.html"> <fancy-button> fancy button </fancy-button>
)5.-*NQPSUT… IUUQTHJUIVCDPNXDXFCDPNQPOFOUTJTTVFTJTTVFDPNNFOU
)5.-.PEVMFT… IUUQTHJTUHJUIVCDPN5BLBZPTIJ,PDIJGEDFEGECCEBGFGF
import fancy from './fancy.html' as HTMLTemplateElement; export class FancyButton extends
HTMLElement { connectedCallback() { this.attachShadow({ mode: 'open' }).appendChild(fancy.content.cloneNode(true)); } }
&4.PEVMFT
&4.PEVMFTהכ ‣ &4.PEVMFTךـٓؐؠ㹋鄲 ‣ TDSJQUUZQFˑNPEVMF˒ד+BWB4DSJQUؿ؋؎ٕٗ٦سׅ ‣ TDSJQUOPNPEVMFדꬊ㼎䘔橆㞮罋䣁ׅ ‣ &4.PEVMFTך/PEFKT㹋鄲 ‣
NKT&4.PEVMFTך+BWB4DSJQUؿ؋؎ٕה׃גٗ٦سׅ
export default class FancyButton { ... } GBODZCVUUPOKT
import React from 'react'; import ReactDOM from 'react-dom'; import PropTypes
from 'prop-types'; import FancyButton from './fancy-button.js'; JOEFYKT
<script type="module"> import FancyButton from './fancy-button.js'; customElements .define('fancy-button', FancyButton); </script>
4IBEPX%0. $VTUPN&MFNFOUT &4.PEVMFT
class FancyButton extends HTMLElement { connectedCallback() { this.attachShadow({ mode: 'open'
}).innerHTML = ` <style>button { … }</style> <button><slot></slot></button> `; } } customElements .define('fancy-button', FancyButton);
export default class FancyButton extends HTMLElement { connectedCallback() { this.attachShadow({
mode: 'open' }).innerHTML = ` <style>button { … }</style> <button><slot></slot></button> `; } }
<fancy-button> fancy button </fancy-button> <script type="module"> import FancyButton from './fancy-button.js';
customElements .define('fancy-button', FancyButton); </script>
8FCחֶֽ鿇ㅷךꨇ׃ׁ ‣ )5.-ה$44חأ؝٦فָ㶷㖈׃זְ ‣ 铣鴥$44ך䕦갟眔㔲ָ鎘濼זְ ‣ せ瑞ָ遼瑱׃זְ״ֲծ䌢ח䠐陎ׅ䗳銲ָ֮ ‣ ⡲鿇ㅷⱄⵃ欽׃חְֻ ‣
)5.- $44 +BWB4DSJQUתה➬穈ָזְ ‣ תה鿇ㅷꂁ䋒ׅؒ؝ءأذيָזַ
4IBEPX%0. $VTUPN&MFNFOUT &4.PEVMFT OQN ZBSO 8FCחֶֽ鿇ㅷךꨇ׃ׁ ‣ )5.-ה$44חأ؝٦فָ㶷㖈׃זְ ‣ 铣鴥$44ך䕦갟眔㔲ָ鎘濼זְ
‣ せ瑞ָ遼瑱׃זְ״ֲծ䌢ח䠐陎ׅ䗳銲ָ֮ ‣ ⡲鿇ㅷⱄⵃ欽׃חְֻ ‣ )5.- $44 +BWB4DSJQUתה➬穈ָזְ ‣ תה鿇ㅷꂁ䋒ׅؒ؝ءأذيָזַ
1PMZNFS4VNNJU JO$PQFOIBHFO
#PXFSJTEFQSFDBUFE
6TFOQN ZBSO
// fancy-button v1.0.0 customElements .define('fancy-button', FancyButton); // fancy-button v1.1.0 customElements
.define('fancy-button', FancyButton); ZBSO⢪ֲץֹ椚歋 ☠ ⣛㶷ٌآُ٦ٕؿٓحزזخٔ٦ד鍑寸דֹ✨
‣ #SPXTFS4VQQPSU ‣ "DDFTTJCJMJUZ ‣ -PBE1FSGPSNBODF ‣ 3FOEFS1FSGPSNBODF
8FC$PNQPOFOUTTBOECPY IUUQTDIHJUIVCJPXFCDPNQPOFOUTTBOECPY
‣ #SPXTFS4VQQPSU ‣ "DDFTTJCJMJUZ ‣ -PBE1FSGPSNBODF ‣ 3FOEFS1FSGPSNBODF
✅ ✅ $VTUPN&MFNFOUTW 4IBEPX%0.W 5FNQMBUFT &4.PEVMFT ✅ ✅ ✅ ✅
✅ ✅ ✅ ✅ ✅ ✅ 䎃猧ـٓؐؠ؟ه٦ز
8FC$PNQPOFOUT JT BWBJMBCMFOPX PO UIFNPCJMFXFC✨
None
:PV5VCFJTCVJMU POUIFUPQPG1PMZNFS
None
6TFXFCDPNQPOFOUTKT ‣ $VTUPN&MFNFOUTWךهٔؿ؍ٕ ‣ 4IBEZ%0.4IBEPX%0.ך%0."1*هٔؿ؍ٕ ‣ 4IBEZ$444IBEPX%0.ךأة؎ٕꟼ鸬هٔؿ؍ٕ ‣ )5.-*NQPSUT
8IZ4IBEZ%0. ‣ %0.خٔ٦ך،ؙإ؟ⵖ䖴ׅךָꨇ׃ְ ‣ ぐ珏%0."1*װ/PEF-JTUךؒىُٖ٦زָꨇ׃ְ ‣ EPDVNFOUCPEZ瘝ך،ؙإ؟♳剅ֹדֹזְ ‣ ؝٦سꆀָ花㣐חז♳ծػؿؓ٦وٝأח䕦갟ׅ
‣ 4IBEZ%0."1*➜׃ג،ؙإأׇׁ ‣ 㸜㹀䚍⥂אאծػؿؓ٦وٝأ⳿ׅ
None
8FC$PNQPOFOUT JTBMTP BWBJMBCMFOPX PO UIFEFTLUPQXFC
‣ #SPXTFS4VQQPSU ‣ "DDFTTJCJMJUZ ‣ -PBE1FSGPSNBODF ‣ 3FOEFS1FSGPSNBODF
"DDFTTJCJMJUZ ‣ 4IBEPX%0.ך)5.-،ؙإءـٕח ‣ 鸐䌢ך%0.ず圫חծإوٝذ؍ؙأ䠐陎ׅ ‣ )5.-ֽד♶⼧ⴓז㜥さכծ8"*"3*"ד؟ه٦زׅ ‣ 孡חזךכأ؝٦فⰻפך،ؙإأ ‣
4IBEPX%0.ָꪪ⳿ׁגְֽ ‣ ،ؙإءؽٔذ؍ָ⡚ְ؝ٝه٦طٝز⢪ֲ㜥さכ˘
<fancy-button> #shadow-root fancy button </fancy-button> <style> button { background: #0086b3;
color: white; padding: 1em; border-radius: 0.5em; border: none; } </style> <button> <slot></slot> </button> &YQPTFE
<fancy-button> #shadow-root fancy button </fancy-button> <style> div { background: #0086b3;
color: white; padding: 1em; border-radius: 0.5em; border: none; } </style> <div role="button" tabindex="0"> <slot></slot> </div> &YQPTFE
‣ #SPXTFS4VQQPSU ‣ "DDFTTJCJMJUZ ‣ -PBE1FSGPSNBODF ‣ 3FOEFS1FSGPSNBODF
-PBE1FSGPSNBODF ‣ TDSJQUח״؝ٝه٦طٝزךٗ٦س ‣ ؙٔؒأز侧כ)551ד֮ל孡ח׃ֺׅזֻג葺ְ ‣ ؝ٝه٦طٝزך+BWB4DSJQUؿ؋؎ٕכNJOJGZׅ ‣ UZQFˑNPEVMF˒㾩䚍ח״EFGFSٗ٦س ‣
ؔفءّٝדBTZOD㾩䚍➰♷דֹ
TDSJQUח״ぐ珏ٗ٦س IUUQTIUNMTQFDXIBUXHPSHNVMUJQBHFTDSJQUJOHIUNMUIFTDSJQUFMFNFOU
ثُ٦صؚٝه؎ٝز ‣ ٔا٦أ㙵鴥ךַٍؗحءُׅךַ ‣ 㙵鴥כ剑傍ֻٖٝتֲָׁؚٔٝծⴱ劍ٗ٦سָ曯暨חז ‣ ״כ$BDIF$POUSPMقحتװ4FSWJDF8PSLFSזודٍؗحءُ׃ְ ‣ ⴱ劍ٗ٦س傍ְ ‣
MJOLSFMˑQSFMPBE˒ד"5'חꟼٔا٦أٗ٦س׃גֶֻ ‣ 如㔐鼂獳ח䗳銲זٔا٦أכMJOLSFMˑQSFGFUDI˒דٗ٦س׃גֶֻ
‣ #SPXTFS4VQQPSU ‣ "DDFTTJCJMJUZ ‣ -PBE1FSGPSNBODF ‣ 3FOEFS1FSGPSNBODF
3FOEFS1FSGPSNBODF ‣ -JHIU%0.ה4IBEPX%0.ך䊴 ‣ 4IBEPX%0.ךךךכـٓؐؠ㹋鄲ך剑黝⻉ח㨻י״ֲ ‣ ע㣐䊴כזְ⦐➂ך✮䟝דׅ ‣ 7JSUVBM%0.ח״䊴ⴓ䲽歗ך⡭㖑 ‣
➙תד鸐3FBDUזוך7JFXٓ؎ـٓٔה穈さׇ ‣ 8FC$PNQPOFOUTⰻד䊴ⴓ䲽歗㹋倵ׅ
import React from 'react'; export default class Button extends React.Component
{ handleClick(e) { if (this.props.onClick) { this.props.onClick(e); } } render() { const handleClick = this.handleClick.bind(this); return ( <fancy-button onClick={handleClick}> {this.props.children} </fancy-button> ); } }
1PMZNFS-BCTMJUIUNM ‣ 5BHHFE5FNQMBUF-JUFSBMדUFNQMBUF⢪ֲ➬穈 ‣ IUNMAAדذٝفٖ٦ز⡲ծSFOEFS ד)5.-欰䧭ׅ ‣ SFOEFS ד床ׅ⹛涸ז鿇ⴓך䊴ⴓ䲽歗ׅ
const helloTemplate = (name) => html`<div>Hello ${name}!</div>`; // renders <div>Hello
Steve!</div> to the document body render(helloTemplate('Steve'), document.body); // updates to <div>Hello Kevin!</div>, but only updates the ${name} part render(helloTemplate('Kevin'), document.body);
import { html, render } from './lit-html.js'; export default class
IconButton extends HTMLElement { connectedCallback() { this.attachShadow({ mode: 'open' }); render(this.template, this.shadowRoot); } get template() { return html` <style>...</style> <button> <i class="${this.getAttribute('icon')}"></i> <slot></slot> </button> `; } };
תה ‣ 8FC$PNQPOFOUTחꟼׅぐ珏➬圫ָ㸜㹀׃גֹ ‣ ـٓؐؠ㹋鄲滠㹋ח鹌ծ暴חٌغ؎ٕ8FCדכه ٔؿ؍ٕז׃ד⢪ִ ‣ ➙⢪גְ䪮遭أةحؙח《鴥דְֽ ‣ ـٓؐؠⰻ鿇Ⳣ椚ך剑黝⻉䖉אאծطحزٙ٦ؙ
ꟼ鸬כ㛇劤ח屟ثُ٦صؚٝד0,
:PVBSFSFBEZUPVTF 8FC$PNQPOFOUT✨
5IBOLZPV !DI "DI