<!-- .slide: data-background-color="var(--spearmint)" --> <div class="content-warning"> <div>Content</div> <div>Advisory</div> <div>Creative Content</div> </div> --- <!-- .slide: data-background-color="var(--fuschia)" --> <img class="qr-intro" src="/shared/images/remote-qr.svg" alt="" /> ## Don't scan this ###### tinyurl.com/jh3y-remote --- <!-- End Deck --><br><!-- .slide: data-background-color="var(--white)" --> <div class="block-reveal"> # Here # we # gooooo! </div> <img class="watermark-bear" src="/shared/images/bear-2022--black.png" alt=""/> --- <!-- End Slide --><br><!-- .slide: class="title-slide" data-background-color="hsl(27 100% 50%)" --> ###### WebExpo 2023 ## Supercharge your skills with creative coding ###### Styling <select>s like it's 2023 <div class="volume-title">Vol. VII</div> --- <!-- End Slide --><br><!-- .slide: class="title-slide title-slide--left" data-background-color="var(--white)" --> ## I'm Jhey Tompkins #### I bring ideas to life<br>with code ##### ~~I work at Google~~ <img class="polaroid" src="/shared/images/bear-baby-chilling.jpg" width="300" /> <!-- <img class="polaroid" src="/shared/images/baby-photo--resized.jpeg" width="300" /> --> --- <!-- End Slide --><br><!-- .slide: data-background-color="var(--white)" data-background-iframe="/demos/voice-range-inputs/basic" data-background-interactive --> --- <!-- .slide: data-background-color="var(--white)" data-background-iframe="/demos/voice-range-inputs/accent-color" data-background-interactive --> --- <!-- .slide: data-background-color="var(--white)" data-background-iframe="/demos/voice-range-inputs/changing-accent-color" data-background-interactive --> --- <!-- .slide: class="title-slide title-slide--top" data-background-color="var(--color-four)" data-background-iframe="/demos/voice-range-inputs/eq-range-inputs" data-background-interactive --> ## Expression through the "impractically practical" --- <!-- .slide: class="title-slide" data-background-color="var(--black)" --> ### Give yourself the <span style="color: var(--citric)">confidence</span> to create <span style="color: var(--fuschia)">anything</span> your imagination brings.<br>Go <span style="color: var(--cinnabar);">beyond documentation</span>, become it. --- <!-- .slide: data-background-video="/shared/video/handshake.mp4" data-background-video-loop="true" data-background-size="cover" data-background-video-muted="true" --> --- <!-- .slide: data-background-color="var(--black)" --> <div class="fuel"> <div class="word-waterfall"> <div data-word="Perspective">Perspective</div> <div data-word="Creativity">Creativity</div> <div data-word="Innovation">Innovation</div> </div> <div class="word-waterfall"> <div data-word="Perspective">Perspective</div> <div data-word="Creativity">Creativity</div> <div data-word="Innovation">Innovation</div> </div> </div> --- <!-- .slide: class="title-slide" data-background-color="var(--black)"--> ## Hoard your <span style="color: var(--citric)">inspiration</span>.<br><span style="color: var(--blueberry)">Focus</span> on <span style="color: var(--fuschia)">"What"</span> and not the "How" or "Why". --- <!-- .slide: data-background-color="var(--black)" --> <div class="demo-row"> <video autoplay controls muted loop src="/shared/video/demo-two.mp4"></video> <video autoplay controls muted loop src="/shared/video/demo-one.mp4"></video> <video autoplay controls muted loop src="/shared/video/demo-three.mp4"></video> </div> --- <!-- .slide: data-background-color="var(--white)" data-background-iframe="/demos/supplementary/boombox-button" data-background-interactive --> --- <!-- .slide: class="title-slide title-slide--right" .slide: data-background-color="var(--black)"--> ## It's a <span style="color: var(--chateau)">personal</span> journey. It's a <span style="color: var(--selective)">process</span>. Something you can <span style="color: var(--fuschia)">train over time</span>. --- <!-- .slide: data-background-color="var(--black)" --> <img src="https://media.giphy.com/media/t79McFW5Yxxff4FP09/giphy.gif" alt="" /> --- <!-- .slide: data-background-color="var(--white)" data-background-iframe="/demos/supplementary/grogu" data-background-interactive --> --- <!-- .slide: class="experimenting-slide" data-background-color="var(--selective)" --> <div class="content-warning"> <div>Content</div> <div>Advisory</div> <div>Experimental Content</div> </div> --- <!-- End Creative Intro<br> <!-- .slide: class="title-slide title-slide--top" data-background-color="var(--chateau)" --> ## It's 2023 and you still can't style a <select class="inline-select"><option>Select</option><option>Style Me?</option><option>Please!</option></select>. That's going to change. --- <!-- .slide: data-background-color="var(--spearmint)" --> <img src="/shared/images/chatgpt-select.png" alt="" /> --- <!-- .slide: data-background-color="var(--selective)" --> <div class="code-split"> <div class="code-stack"> ```html <select name=font-size id=size> <option value=normal>Normal</option> <option value=title>Title</option> <option value=subtitle>Subtitle</option> <option value=footnote>Title</option> </select> ``` ```css /* Give visual context to our <select> */ [value=title] { font-size: 2rem; } [value=normal] { font-size: 1rem; } ``` </div> <iframe class="demo-embed" src="/demos/openui-selectmenu/attempting-select"></iframe> </div> --- <!-- .slide: data-background-color="var(--cinnabar)" --> <div class="code-split"> <div class="code-stack"> ```html <button>Select Font Size</button> <div role=listbox> <option value=normal>Normal</option> <option value=title>Title</option> <option value=subtitle>Subtitle</option> <option value=footnote>Title</option> </div> ``` ```css /* Give visual context to our <select> */ [value=title] { font-size: 2rem; } [value=normal] { font-size: 1rem; } ``` </div> <iframe class="demo-embed" src="/demos/openui-selectmenu/the-components"></iframe> </div> --- <!-- .slide: data-background-color="var(--blueberry)" --> <div class="code-split"> <div class="code-stack"> ```html [1,9] <div class=selectmenu> <button>Select Font Size</button> <div role=listbox> <option value=normal>Normal</option> <option value=title>Title</option> <option value=subtitle>Subtitle</option> <option value=footnote>Title</option> </div> </div> ``` ```css /* Give visual context to our <select> */ .selectmenu { position: relative; } [role=listbox] { position: absolute; top: 100%; left: 0; } ``` </div> <iframe class="demo-embed" src="/demos/openui-selectmenu/anchoring-attempt"></iframe> </div> --- <!-- .slide: data-background-color="var(--selective)" --> <div class="code-split"> <div class="code-stack"> ## Uh oh </div> <iframe class="demo-embed" src="/demos/openui-selectmenu/rudimentary-anchoring-issue"></iframe> </div> --- <!-- End Section <br>.slide: data-background-color="var(--blueberry)" class="title-slide title-slide--bottom" --> ## CSS Anchoring --- <!-- .slide: data-background-color="var(--white)" --> <div class="support-grid"> <span class="browser-logo" data-browser="canary"></span> <span class="browser-logo" data-browser="chrome"></span> <span class="browser-logo" data-browser="edge"></span> <span class="browser-logo" data-browser="safari"></span> <span class="browser-logo" data-browser="firefox"></span> <span class="browser-version" data-supported> <span class="material-symbols-outlined"> flag </span> </span> <span class="browser-version">×</span> <span class="browser-version">×</span> <span class="browser-version">×</span> <span class="browser-version">×</span> </div> --- <!-- .slide: data-background-color="var(--citric)" --> <img src="/tpac-2022/assets/tooltip-anatomy.png" /> --- <!-- .slide: data-background-color="var(--off-white)" --> <div class="code-split"> <div class="code-stack"> ```html <div class="boat"></div> <div class="anchor"></div> ``` ```css .anchor { anchor-name: --anchor; } .boat { top: anchor(--anchor bottom); left: anchor(--anchor right); } ``` </div> <iframe class="demo-embed" src="/demos/css-anchoring/basic-boat"></iframe> </div> --- <!-- .slide: data-background-color="var(--selective)" --> <div class="code-split"> <div class="code-stack"> ```css .anchor { anchor-name: --anchor; } .boat { position-fallback: --compass; } @position-fallback --compass { @try { bottom: anchor(--anchor top); right: anchor(--anchor left); } @try { bottom: anchor(--anchor top); left: anchor(--anchor right); } } ``` </div> <iframe class="demo-embed" src="/demos/css-anchoring/fallback-boat"></iframe> </div> --- <!-- .slide: data-background-iframe="/demos/css-anchoring/tooltip-fallback" --> --- <!-- .slide: data-background-iframe="/demos/css-anchoring/album-menu" --> --- <!-- .slide: data-background-color="var(--fuschia)" --> <!-- <div class="code-split"> <div class="code-stack"> ```html <!-- Caveat --> <!-- <div class="ice-cream-wrapper"> <div class="ice-creame-cone"></div> </div> <div class="ice-cream"></div> ``` ```css .ice-cream-cone { anchor-name: --cone; } .ice-cream { position-fallback: --sundae; } @position-fallback --sundae { @try { bottom: anchor(--cone top); left: anchor(--cone center); } @try { bottom: anchor(--floor top); left: anchor(--floor center); } } ``` </div> <iframe class="demo-embed" src="/demos/css-anchoring/fallback-ice-cream"></iframe> </div> --> ```css[|2,7|12-15] #share { anchor-default: --share; position-fallback: --aligned; } #playlist { anchor-default: --playlist; position-fallback: --aligned; } @position-fallback --aligned { @try { top: anchor(top); left: anchor(right); } @try { top: anchor(bottom); left: anchor(right); } @try { top: anchor(top); right: anchor(left); } @try { bottom: anchor(bottom); left: anchor(right); } @try { right: anchor(left); bottom: anchor(bottom); } } ``` --- <!-- .slide: data-background-color="var(--theme-5)" --> <div class="code-split code-split--inverted"> <iframe class="demo-embed" src="/demos/css-anchoring/anchor-charts"></iframe> <div class="code-stack"> ```css .chart__tooltip--max { position: absolute; left: anchor(--chart right); bottom: max( anchor(--anchor-1 top), anchor(--anchor-2 top), anchor(--anchor-3 top) ); translate: 0 50%; } ``` </div> </div> --- <!-- .slide: data-background-color="var(--blueberry)" --> ```css[] .anchored { position: absolute; border: 10px dashed var(--text-1); top: min(anchor(--a1 center), anchor(--a2 center)); left: min(anchor(--a1 center), anchor(--a2 center)); right: min(anchor(--a1 center), anchor(--a2 center)); bottom: min(anchor(--a1 center), anchor(--a2 center)); } ``` --- <!-- .slide: data-background-iframe="/demos/css-anchoring/multiple-anchors" --> --- <!-- .slide: data-background-iframe="/demos/css-anchoring/image-resize" --> --- <!-- .slide: data-background-iframe="/demos/css-anchoring/four-quadrants" --> --- <!-- .slide: data-background-color="var(--cinnabar)" --> ```css[] /* Top left */ .annotation div:nth-of-type(1) { background: hsl(10 80% 50% / 0.5); top: anchor(var(--anchor-two) center); right: anchor(var(--anchor-one) center); bottom: anchor(var(--anchor-one) center); left: anchor(var(--anchor-two) center); } /* Top right */ .annotation div:nth-of-type(2) { background: hsl(210 80% 50% / 0.5); top: anchor(var(--anchor-two) center); right: anchor(var(--anchor-two) center); bottom: anchor(var(--anchor-one) center); left: anchor(var(--anchor-one) center); } ``` --- <!-- .slide: data-background-iframe="/demos/css-anchoring/post-it-board" --> --- <!-- .slide: data-background-color="var(--citric)" --> ```css[] :root { --active-anchor: --name; } #name { anchor-name: --name; } .form-indicator { left: var(--active-left); top: var(--active-top); } :root:has(#email:focus) { --active-anchor: --email; } ``` --- <!-- .slide: data-background-iframe="/demos/css-anchoring/transitional" --> --- <!-- .slide: data-background-iframe="/demos/css-anchoring/transition-cursor-menu" --> --- <!-- .slide: data-background-color="var(--spearmint)" --> ```css[] :root:has([href="/blog"]:is(:hover, :focus-visible)) { --active: --blog; } ``` --- <!-- .slide: data-background-color="var(--citric)" --> ```css .bear__paw { top: anchor(var(--anchor-name) center); left: anchor(--form right); } #password { anchor-name: --password; } :root:has(#password:focus) { --anchor-name: var(--password) } /* Bonus:: Position a password reveal */ .password-reveal { position: absolute; right: anchor(--password right); top: anchor(--password center); translate: 0 -50%; } ``` --- <!-- .slide: data-background-iframe="/demos/css-anchoring/bear-form" --> --- <!-- End Section<br> <!-- .slide: class="title-slide title-slide--top" data-background-color="var(--selective)" --> ## We can now anchor our dropdown to our button! 🎉 --- <!-- .slide: data-background-color="var(--fuschia)" --> <div class="code-split"> <div class="code-stack"> ```html <button>Select Font Size</button> <div role=listbox> <option value=normal>Normal</option> <option value=title>Title</option> <option value=subtitle>Subtitle</option> <option value=footnote>Title</option> </div> ``` ```css /* Give visual context to our <select> */ [value=title] { font-size: 2rem; } [value=normal] { font-size: 1rem; } ``` </div> <iframe class="demo-embed" src="/demos/openui-selectmenu/the-components"></iframe> </div> --- <!-- .slide: data-background-color="var(--blueberry)" --> <div class="code-split"> <div class="code-stack"> ```html <button>Select Font Size</button> <div role=listbox> <option value=normal>Normal</option> <option value=title>Title</option> <option value=subtitle>Subtitle</option> <option value=footnote>Title</option> </div> ``` ```css button { anchor-name: --selectmenu; } [role=listbox] { position: absolute; top: anchor(--selectmenu bottom); left: anchor(--selectmenu left); } ``` </div> <iframe class="demo-embed" src="/demos/openui-selectmenu/tethering"></iframe> </div> --- <!-- .slide: data-background-color="var(--selective)" --> <div class="code-split"> <div class="code-stack"> <h2 style="text-align: left;">Uh oh.<br>Wrapping elements<br>aren't the problem.</h2> </div> <iframe class="demo-embed" src="/demos/openui-selectmenu/rudimentary-tethering-issue"></iframe> </div> --- <!-- End Section <br><!-- .slide: class="title-slide title-slide--top" data-background-color="var(--cinnabar)" --> ## Open UI ~~Pop-up~~<br>Popover --- <!-- .slide: data-background-color="var(--white)" --> <div class="support-grid"> <span class="browser-logo" data-browser="canary"></span> <span class="browser-logo" data-browser="chrome"></span> <span class="browser-logo" data-browser="edge"></span> <span class="browser-logo" data-browser="safari"></span> <span class="browser-logo" data-browser="firefox"></span> <span class="browser-version" data-supported> <span class="material-symbols-outlined"> flag </span> </span> <span class="browser-version">×</span> <span class="browser-version">×</span> <span class="browser-version">×</span> <span class="browser-version">×</span> </div> --- <!-- .slide: class="title-slide title-slide--bottom" data-background-color="var(--black)" --> ## The goal of the <span style="color: var(--citric);">Open UI</span> initiative is to make it <span style="color: var(--blueberry)">easier</span> for developers to make <span style="color: var(--fuschia);">great user experiences</span> --- <!-- .slide: data-background-color="var(--citric)" --> ```jsx [] const PopUp = ({ children }) => { return ( <div className="pop-up" style={{ zIndex: Date.now() }}> {children} </div> ) } ``` --- <!-- .slide: class="title-slide title-slide--bottom" data-background-image="/shared/images/king.jpg" data-background-opacity="0.4" --> ## What's the top layer? A place outside of the <span style="background-color: var(--cinnabar);">document</span> flow. A place where <span style="background-color: var(--chateau);">z-index</span> has no effect. Where every element has a styleable <span style="background-color: var(--selective);">::backdrop</span>. <!-- --- --> <!-- slide: data-background-color="var(--cinnabar)" --> <!-- ```js [] // Current ways to get into the "Top Layer" Dialog.showModal(); Element.requestFullscreen(); ``` --- --> <!-- ```html [] <div id="my-first-popup" popup>PopUp Content!</div> <button popuptoggletarget="my-first-popup">Toggle Pop-Up</button> ``` <iframe src="/demos/openui-pop-ups/first" class="demo-embed"></iframe> --- --> --- <!-- .slide: data-background-color="hsl(0 0% 100%)" data-background-iframe="/demos/openui-pop-ups/with-backdrop" --> --- <!-- .slide: data-background-color="var(--fuschia)" --> ```html [8,9,11] <html> <head> <title>First Pop-up</title> </head> <body> <main> <!-- Throw all your z-index at me! --> <button popovertarget="my-first-popover" popovertargetaction="toggle"> </button> <!-- Don't care where this is to be honest --> <div id="my-first-popover" popover>Dobrý den! 👋</div> <header> <h1>Awesome Website</h1> </header> <article> <p> Lorem ipsum dolor sit...</p> </article> </main> </body> </html> ``` --- <!-- .slide: data-background-color="var(--black)" class="title-slide slide--top" --> ## <span style="color:var(--fuschia)">popovertargetaction</span> attribute is looong. <h3 style="text-align:right;">– <span style="opacity: 0.5; color: var(--selective);">Someone, no doubt.</span></h3> --- <!-- .slide: data-background-color="var(--off-white)" --> <ul class="bullets"> <li>Hidden by default</li> <li>No JavaScript</li> <li>No z-index fighting</li> <li>Light dismiss</li> <li>Anywhere in the DOM</li> </ul> --- <!-- .slide: class="title-slide title-slide--top" data-background-color="var(--black)" --> ## <span style="color: var(--fuschia)">Better developer experience</span> leads to less opportunity for poor <span style="color: var(--citric)">user experience</span> --- <!-- .slide: data-background-color="var(--citric)" --> ```css [|11|11-16] [popover] { transform: translate(-50%, -50%) translateY(calc((1 - var(--open, 0)) * 100vh)) scale(var(--open, 0)); transition-property: transform, display, overlay; transition-duration: 0.25s; transition-timing-functions: var(--ease-elastic-4); } [popover]:popover-open { @initial { --open: 0; } --open: 1; } ``` --- <!-- .slide: data-background-iframe="/demos/openui-pop-ups/3d-popover" --> --- <!-- slide: data-background-color="hsl(0 0% 100%)" data-background-iframe="/demos/openui-pop-ups/balloon-animation" --> <!-- --- --> <!-- ```css [] @media (prefers-reduced-motion: no-preference) { [popover] { animation: exit-animation 250ms ease-out both; } [popover]:open { animation: entry-animation 1s ease-in both; } @keyframes exit-animation { 100% { transform: translate(-50%, -50%) translateY(-100vh) scale(0); } } @keyframes entry-animation { 0% { transform: translate(-50%, -50%) translateY(100vh) scale(0); } } } ``` --> <!-- --- --> <!-- slide: class="title-slide title-slide--left" data-background-color="var(--cinnabar)" --> <!-- ## Types && Behavior --- --> <!-- .slide: data-background-color="var(--citric)" --> ## Types && Behavior ```html [] <!-- Nesting support --> <div popover=auto> <!-- Explicit dismiss --> <div popover=manual> <!-- Triggers --> <button popovertarget=pop popovertargetaction=toggle> <button popovertarget=pop popovertargetaction=show> <button popovertarget=pop popovertargetaction=hide> <!-- Open on render --> <!-- ~~<div popover defaultopen>~~ 🥲 --> <!-- ~~popover=hint~~ 🥲 --> <!-- Focus management --> <div popover> <input autofocus type="text"> </div> ``` --- <!-- - Nesting support via ancestral pop-ups - Dismisses pop-ups that aren't ancestral - Dismissing in the stack only dismisses those above --- --> <!-- slide: data-background-color="hsl(0 0% 100%)" data-background-iframe="/demos/openui-pop-ups/auto" --> <!-- --- ```html [|3] <div id="blue-two" class="blue" popover> <div class="card elevated"> <button popovershowtarget="red-one" class="button ripple"> Take first red candy </button> <button popovershowtarget="blue-three" class="button ripple"> Take another blue candy </button> <button popoverhidetarget="blue-two" class="button ripple"> Put this candy back </button> <button popoverhidetarget="blue-one" class="button ripple"> Put back blue candies </button> </div> </div> ``` --> <!-- --- --> <!-- ## Hint ```html [] <div popover=hint> ``` --- --> <!-- - Singleton - Doesn't dismiss other types - Can't use `defaultopen` --- --> <!-- slide: data-background-color="hsl(0 0% 100%)" data-background-iframe="/demos/openui-pop-ups/hint" --> <!-- --- ```html [|3] <div id="blue-pill" class="blue" popover="hint"> <div class="card elevated"> <button popovershowtarget="red-pill" class="button ripple"> Actually, take the red pill </button> <button popoverhidetarget="blue-pill" class="button ripple"> Still deciding </button> </div> </div> ``` --- --> <!-- ## Manual ```html [] <div popover=manual> ``` --- --> <!-- - Doesn't dismiss others - No light dismiss - Only closed explicitly via trigger or JavaScript --- --> <!-- slide: data-background-color="hsl(0 0% 100%)" data-background-iframe="/demos/openui-pop-ups/manual" --> <!-- --- ```html [|6,14] <div popover="manual" defaultopen id="window"> <div class="window"> <div class="title-bar"> <div class="title-bar-text">Manual Pop-up</div> <div class="title-bar-controls"> <button aria-label="Close" popoverhidetarget="window"></button> </div> </div> <div class="window-body"> <p> The only way to remove me is via a trigger element, or with JavaScript. </p> <button popoverhidetarget="window">Close</button> </div> </div> </div> ``` --> <!-- --- --> <!-- .slide: data-background-color="var(--selective)" --> ## JS API ```js [] /* Show a popover */ popoverElement.showPopover() /* Hide a popover */ popoverElement.hidePopover() /* Is the popover in the top layer */ popoverElement.matches(':popover-open') /* Listen for popover events */ const onToggle = ({ preventDefault, currentState, newState }) => { /* You can cancel a show */ if (newState === "open") preventDefault() else if (newState === "closed") console.warn("You can't cancel hiding a popover") } popoverElement.addEventListener('beforetoggle', onToggle) popoverElement.addEventListener('toggle', onToggle) ``` --- <!-- .slide: data-background-color="hsl(0 0% 100%)" data-background-iframe="/demos/openui-pop-ups/retro-poppers" --> --- <!-- ```html [] <button popover="manual" class="balloon" id="P" defaultopen title="Pop 'P'" style="--index: -2.5; --hue: 107; --bob-speed: 1; --float-speed: 0.9;" > <span class="balloon__content"> <span class="balloon__letter">P</span> <span class="balloon__handle"></span> </span> </button> ``` <div> ```js [] POPUP.addEventListener("click", () => { AUDIO_POP.currentTime = 0; AUDIO_POP.play(); POPUP.hidePopover(); Object.assign(POPUP, { style: ` --index: ${START_INDEX + p}; --hue: ${Math.random() * 359}; --bob-speed: ${Math.random() + 0.5}; --float-speed: ${Math.random() + 0.5}; ` }); requestAnimationFrame(() => POPUP.showPopover()); }); ``` </div> --> <!-- --- --> <!-- ## Accessibility && Focus ```html [|4] <div id="input-pop-up" popover> <div class="card elevated"> <label for="name">Name</label> <input id="name" autofocus type="text"> <button class="button ripple" popoverhidetarget="input-pop-up">Close</button> </div> </div> ``` --- --> <!-- slide: data-background-color="hsl(0 0% 100%)" data-background-iframe="/demos/openui-pop-ups/autofocus" --> <!-- --- --> <!-- .slide: class="title-slide title-slide--top" data-background-color="var(--fuschia)"--> ## Breathe new life into old friends? --- <!-- ### Nav Drawer --- --> <!-- .slide: data-background-color="var(--white)" data-background-iframe="/demos/openui-pop-ups/bear-nav" --> --- <!-- .slide: data-background-color="var(--citric)" class="code-stack" --> <div> ```html [] <button popovertarget=menu> Toggle Menu </button> <div popover id=menu role=menu> <!-- Nav Content --> </div> ``` </div><div> ```css [|13-19|21-23] [popover] { left: 100%; width: var(--nav-width); transition: transform 0.2s; transform: translateX(calc(var(--open, 0) * -100%)); } [popover]::backdrop { transition: opacity 0.2s; opacity: var(--open, 0); } [popover]:popover-open { @initial { --open: 0; &::backdrop { --open: 0; } } &::backdrop { --open: 1; } --open: 1; } body:has([popover]:popover-open) { transform: translateX(calc(var(--nav-width) * -1)); } ``` </div> --- <!-- ### Custom Cursor --- --> <!-- .slide: data-background-color="hsl(0 0% 100%)" data-background-iframe="/demos/openui-pop-ups/cursor-cloud" --> <!-- .slide: data-background-color="hsl(0 0% 100%)" data-background-iframe="/demos/openui-pop-ups/custom-cursor" --> --- <!-- <div> ```html [] <canvas id="custom-cursor" class="custom-cursor" popover="manual" defaultOpen ></canvas> ``` </div> ```js [] document.body.addEventListener("popovershow", (e) => { if (canvas.matches(":open") && e.target !== canvas) { canvas.hidePopover(); requestAnimationFrame(() => { canvas.showPopover(); }); } }); ``` --- --> <!-- ### Toasts --- --> <!-- .slide: data-background-color="hsl(0 0% 100%)" data-background-iframe="/demos/openui-pop-ups/real-toast" --> <!-- --- ```html [] <div popover="manual" class="toasts"> <ul class="toasts__drawer"> </ul> </div> ``` --> --- <!-- ### Command Palette --- --> <!-- .slide: data-background-color="hsl(0 0% 100%)" data-background-iframe="/demos/openui-pop-ups/command-palette" --> --- <!-- .slide: data-background-color="var(--selective)" --> ```html [] <div id="spotlight" popover> <input autocomplete="off" role="combobox" spellcheck="false" aria-expanded="false" aria-controls="spotlight-options" aria-activedescendant="" autofocus id="spotlight-search" type="text" placeholder="Pop-up search..." /> <div popover id="spotlight-options" role="listbox"> <!-- "Options" get injected here --> </div> </div> ``` --- <!-- --- ```js [] /* Show the pop-up then you get light dismiss etc. for free! */ const handleActivation = (e) => { if (e.keyCode === CMD && !STATE.cmd) STATE.cmd = true; if (e.keyCode === MOD && STATE.cmd && !STATE.mod) STATE.mod = true; if (STATE.cmd && STATE.mod && !POPUP.matches(":open")) { STATE.cmd = STATE.mod = false; POPUP.showPopover(); OPTIONS.showPopover(); } }; ``` --> <!-- --- ### Screensaver --- --> <!-- .slide: data-background-color="var(--white)" data-background-iframe="/demos/openui-pop-ups/popover-matrix" --> --- <!-- .slide: class="code-stack" data-background-color="var(--fuschia)" --> <div> ```html [] <canvas id="rain" class="rain" popover="auto" ></canvas> ``` </div> <div> ```js [] // General idea! 💡 if (!SCREENSAVER.matches(":popover-open")) { screensaverTimeout = setTimeout(() => { SCREENSAVER.showPopover(); }, SCREENSAVER_THRESHOLD); } ``` </div> --- <!-- ### Floating Actions --- --> <!-- slide: data-background-color="hsl(0 0% 100%)" data-background-iframe="/demos/openui-pop-ups/floating-action" --> <!-- --- --> <!-- .slide: style="--code-size: 0.325em;" --> <!-- ```html [] <button class="fab secondary" popover="manual" defaultopen popovertoggletarget="menu" > <i class="material-icons">add</i> </button> <div id="menu" class="fab__menu" popover="auto" style="--count: 3"> <ul class="fab__menu-items"> <li class="fab__menu-item"> <button autofocus class="fab" style="--index: 0" popoverhidetarget="menu" > <i class="material-icons">chat</i> </button> </li> <li class="fab__menu-item"> <button class="fab" style="--index: 1" popoverhidetarget="menu" > <i class="material-icons">photo_camera</i> </button> </li> <li class="fab__menu-item"> <button class="fab" style="--index: 2" popoverhidetarget="menu" > <i class="material-icons">pin_drop</i> </button> </li> </ul> </div> ``` --- --> <!-- ### Webcam --- --> <!-- .slide: data-background-color="hsl(0 0% 100%)" data-background-iframe="/demos/openui-pop-ups/webcam-throw" --> --- <!-- .slide: style="--code-size: 0.325em;" data-background-color="var(--spearmint)" --> ```html [] <button popover="manual" popovertarget="menu" > <i class="material-icons">add</i> </button> <div id="menu" class="fab__menu" popover="auto" style="--count: 3"> <ul class="fab__menu-items"> <li class="fab__menu-item"> <button autofocus class="fab" style="--index: 0" popovertarget="menu" > <i class="material-icons">chat</i> </button> </li> <li class="fab__menu-item"> <button class="fab" style="--index: 1" popovertarget="camera" > <i class="material-icons">photo_camera</i> </button> </li> <li class="fab__menu-item"> <button class="fab" style="--index: 2" popovertarget="menu" > <i class="material-icons">pin_drop</i> </button> </li> </ul> </div> ``` --- <!-- .slide: data-background-color="var(--citric)" --> <h2 style="text-align:left;"><a style="color: var(--black);"target="_blank" href="/demos/device/devicemotion-notifications-popover">Let's look at<br>gestures! 👈 <span style="opacity: 0.25;">(Click this!)</span></a></h2> --- <!-- .slide: data-background-color="hsl(0 0% 100%)" data-background-iframe="/demos/openui-pop-ups/strange-portal" --> --- <!-- .slide: data-background-color="hsl(0 0% 100%)" data-background-iframe="/demos/openui-pop-ups/error-heaven" --> --- <!-- .slide: data-background-color="hsl(0 0% 100%)" data-background-iframe="/demos/openui-pop-ups/popover-pinata" --> --- <!-- End Section<br> <!-- .slide: class="title-slide title-slide--top" data-background-color="var(--off-white)" --> ### Now we can anchor our dropdown and get it above everything else! ✨ --- <!-- .slide: data-background-color="var(--blueberry)" --> <div class="code-split"> <div class="code-stack"> ```html <button>Select Font Size</button> <div role=listbox> <option value=normal>Normal</option> <option value=title>Title</option> <option value=subtitle>Subtitle</option> <option value=footnote>Title</option> </div> ``` ```css /* Give visual context to our <select> */ [value=title] { font-size: 2rem; } [value=normal] { font-size: 1rem; } ``` </div> <iframe class="demo-embed" src="/demos/openui-selectmenu/the-components"></iframe> </div> --- <!-- .slide: data-background-color="var(--blueberry)" --> <div class="code-split"> <div class="code-stack"> ```html [2,3] <div class=selectmenu> <button popovertarget=menu>Select Font Size</button> <div id=menu role=listbox popover> <option value=normal>Normal</option> <option value=title>Title</option> <option value=subtitle>Subtitle</option> <option value=footnote>Title</option> </div> </div> ``` ```css button { anchor-name: --selectmenu; } [role=listbox] { position: absolute; width: anchor-size(--selectmenu width); top: anchor(--selectmenu bottom); left: anchor(--selectmenu left); } ``` </div> <iframe class="demo-embed" src="/demos/openui-selectmenu/combining"></iframe> </div> --- <!-- .slide: data-background-color="var(--citric)" --> <div class="code-split"> <div class="code-stack"> ## It works! 🙌 </div> <iframe class="demo-embed" src="/demos/openui-selectmenu/no-issues"></iframe> </div> --- <!-- End Section <br><!-- .slide: class="title-slide title-slide--top" data-background-color="var(--spearmint)" --> <h2> <del>It's 2022 and I can't style a <select>?</del> <br> Open UI SelectMenu </h2> --- <!-- .slide: data-background-color="var(--white)" --> <div class="support-grid"> <span class="browser-logo" data-browser="canary"></span> <span class="browser-logo" data-browser="chrome"></span> <span class="browser-logo" data-browser="edge"></span> <span class="browser-logo" data-browser="safari"></span> <span class="browser-logo" data-browser="firefox"></span> <span class="browser-version" data-supported> <span class="material-symbols-outlined"> flag </span> </span> <span class="browser-version">×</span> <span class="browser-version">×</span> <span class="browser-version">×</span> <span class="browser-version">×</span> </div> --- <!-- .slide: data-background-color="var(--blueberry)" --> <div class="code-stack"> ```html <select name=font-size id=size> <option value=normal>Normal</option> <option value=title>Title</option> <option value=subtitle>Subtitle</option> <option value=footnote>Title</option> </select> ``` ```css [value=title] { font-size: 2rem; } ``` </div> --- <!-- .slide: data-background-iframe="/demos/openui-selectmenu/attempting-select" data-background-color="var(--spearmint)" --> --- <!-- .slide: data-background-color="var(--citric)" --> ```html [|1,6] <selectmenu name=font-size id=size> <option value=normal>Normal</option> <option value=title>Title</option> <option value=subtitle>Subtitle</option> <option value=footnote>Title</option> </selectmenu> ``` --- <!-- .slide: data-background-color="var(--selective)" data-background-iframe="/demos/openui-selectmenu/font-size-select" --> --- <!-- .slide: data-background-color="var(--selective)" data-background-iframe="/demos/openui-selectmenu/highlights" --> --- <!-- .slide: data-background-color="var(--fuschia)" --> ```html [|3,4,5,6,7,8,11,12,13,14,15,16|2,9,10,17] <selectmenu id="country"> <div slot="button"> <button behavior="button"> <span behavior="selected-value" slot="selected-value"> <span>Czech Republic</span> <img src="./cr.png" alt=""> </span> </button> </div> <div slot=listbox> <div popover behavior=listbox> <option value=CzechRepublic> <img src="./cr.png" alt=""> <span>Czech Republic</span> </option> </div> </div> </selectmenu> ``` --- <!-- .slide: data-background-iframe="/demos/openui-selectmenu/country-select" data-background-color="var(--blueberry)" --> --- <!-- .slide: data-background-iframe="/demos/openui-selectmenu/radial-select" data-background-color="var(--off-white)" --> --- <!-- .slide: data-background-iframe="/demos/openui-selectmenu/dial-select" data-background-color="var(--off-white)" --> --- <!-- .slide: data-background-color="var(--citric)" --> ```html [|3,5,6,7,9,10] <selectmenu> <div slot="button"> <button behavior="button" disabled={loading}> <span className="pokeselect__image-placeholder"> {loading && <img className="pokeselect__ball" src="poke-ball.png" alt="" />} {!loading && !selected && <img className="pokeselect__choose" src="question.png" alt="" />} {selected && <img className="pokeselect__avatar" src={selected.avatar} alt=""/>} </span> {!selected && <span className="pokeselect__placeholder">Select Pokémon</span>} {selected && <span>{selected.name}</span>} <svg viewBox="0 0 320 512" title="marker"></svg> </button> </div> <div slot="listbox"> <div popover="auto" behavior="listbox"> <!-- Here go the options populated from the Poké API --> </div> </div> </selectmenu> ``` --- <!-- .slide: data-background-iframe="/demos/openui-selectmenu/pokeselect" --> --- <!-- .slide: data-background-iframe="/demos/openui-selectmenu/cyberpunk-select" --> --- <!-- .slide: data-background-color="var(--fuschia)" --> ```css :root { --transition-step: 0.1s; --transition: 0.2s; --total-transition: calc( ((var(--options) + 1) * var(--transition-step)) + var(--transition) ); } [popover] { /* Gotta wait! */ transition: opacity var(--total-transition), display var(--total-transition), overlay var(--total-transition); } ``` --- <!-- .slide: data-background-iframe="/demos/openui-selectmenu/emoji-picker" --> --- <!-- .slide: data-background-iframe="/demos/openui-selectmenu/3d-sushi" --> --- <!-- .slide: data-background-iframe="/demos/openui-selectmenu/tuggable-select" --> --- <!-- .slide: data-background-iframe="/demos/openui-selectmenu/sock-selector" --> --- <!-- .slide: data-background-iframe="/demos/openui-selectmenu/parachute-bears" --> --- <!-- End Section<br> <!-- .slide: class="title-slide title-slide--top" data-background-color="var(--chateau)" --> ## That's it.<br>Styleable <select>s are coming. --- <!-- .slide: class="title-slide title-slide--right" --> ## If you haven't, <span style="color: var(--fuschia)">start</span> your journey. <span style="color: var(--selective)">Supercharge</span> yourself. It's <span style="color: var(--blueberry)">just pixels</span>. --- <!-- .slide: class="title-slide" --> ## The more you <span style="color: var(--fuschia)">"play"</span> around, the more you are gonna <span style="color:var(--chateau)">find out</span> --- <!-- .slide: class="title-slide title-slide--top" data-background-color="var(--black)" --> <!-- ## <span style="color: var(--selective)">We</span>'re here to <span style="color: var(--chateau)">help!</span> --> <!-- <img class="chrome-logo" src="/shared/images/chrome-logo.svg"> --> <!-- --- --> <!-- End Section<br><!-- .slide: data-background-color="var(--black)" data-background-iframe="https://cdpn.io/pen/debug/gOPmMyO"--> <h2 class="stay-awesome">Stay Awesome!</h2> <!-- End Deck --><br>
@jh3yy