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.1k
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.3k
EU のデジタル市場法と Apple / DMA and Apple
1000ch
0
130
Web Share API
1000ch
0
150
2023 年の Web 開発のベースライン / Web Development Baseline 2023
1000ch
0
60
開発生産性と組織 / Productivity and Organization
1000ch
0
1.2k
なぜ私達は働くのか / Why We Work?
1000ch
0
89
新しいメルカリ Web とそのパフォーマンス / The New Mercari Web and its performance
1000ch
0
96
Web Standards Interop 2022
1000ch
0
330
パフォーマンスを高める CSS / Performance Optimized CSS
1000ch
1
830
Other Decks in Technology
See All in Technology
【CEDEC2025】『ウマ娘 プリティーダービー』における映像制作のさらなる高品質化へ!~ 豊富な素材出力と制作フローの改善を実現するツールについて~
cygames
PRO
0
240
2025-07-31: GitHub Copilot Agent mode at Vibe Coding Cafe (15min)
chomado
2
380
AI時代の経営、Bet AI Vision #BetAIDay
layerx
PRO
1
1.8k
Google Agentspaceを実際に導入した効果と今後の展望
mixi_engineers
PRO
3
350
Tableau API連携の罠!?脱スプシを夢見たはずが、逆に依存を深めた話
cuebic9bic
3
210
みんなのSRE 〜チーム全員でのSRE活動にするための4つの取り組み〜
kakehashi
PRO
2
140
Nx × AI によるモノレポ活用 〜コードジェネレーター編〜
puku0x
0
390
Claude Codeが働くAI中心の業務システム構築の挑戦―AIエージェント中心の働き方を目指して
os1ma
9
1.6k
o11yツールを乗り換えた話
tak0x00
2
470
風が吹けばWHOISが使えなくなる~なぜWHOIS・RDAPはサーバー証明書のメール認証に使えなくなったのか~
orangemorishita
15
5.6k
마라톤 끝의 단거리 스퍼트: 2025년의 AI
inureyes
PRO
1
700
【CEDEC2025】『Shadowverse: Worlds Beyond』二度目のDCG開発でゲームをリデザインする~遊びやすさと競技性の両立~
cygames
PRO
1
300
Featured
See All Featured
Speed Design
sergeychernyshev
32
1.1k
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
283
13k
A Tale of Four Properties
chriscoyier
160
23k
Building Better People: How to give real-time feedback that sticks.
wjessup
367
19k
How to train your dragon (web standard)
notwaldorf
96
6.2k
Gamification - CAS2011
davidbonilla
81
5.4k
Balancing Empowerment & Direction
lara
1
530
Become a Pro
speakerdeck
PRO
29
5.5k
What's in a price? How to price your products and services
michaelherold
246
12k
Statistics for Hackers
jakevdp
799
220k
Fantastic passwords and where to find them - at NoRuKo
philnash
51
3.4k
The World Runs on Bad Software
bkeepers
PRO
70
11k
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