Yes, Your Browser Can Do That (Probably)

A presentation at Web Directions Code in June 2024 in Melbourne VIC, Australia by Julian Burr

Slide 1

Slide 1

YES, YOUR BROWSER CAN (probably) DO THAT___ A Look At Modern Web APIs You Might Not Know JULIAN BURR @ WEB DIRECTIONS CODE 2024

Slide 2

Slide 2

Progressive enhancement is a design philosophy that provides a baseline of essential content and functionality to as many users as possible while delivering the best possible experience only to users of the most modern browsers https://developer.mozilla.org/docs/Glossary/Progressive_Enhancement

Slide 3

Slide 3

stopme.io The ultimate SaaS (Stopwatch as a Service) product for everyone

Slide 4

Slide 4

Observe your APP …

Slide 5

Slide 5

01 Resize & Intersection Observer

Slide 6

Slide 6

01 Resize & Intersection Observer const callback = (entries) => { entries.forEach((entry) => { // *.contentBoxSize }); } const observer = new ResizeObserver(callback, options); const el = document.querySelector(“element”); observer.observe(el); https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver

Slide 7

Slide 7

01 Resize & Intersection Observer const callback = (entries) => { entries.forEach((entry) => { // *.isIntersecting // *.intersectionRect // *.intersectionRatio // … }); } const observer = new IntersectionObserver(callback, options); const el = document.querySelector(“element”); observer.observe(el); https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API

Slide 8

Slide 8

… And the user’s Device

Slide 9

Slide 9

02 Network Information API

Slide 10

Slide 10

02 Network Information API // Online status let isOnline = navigator.onLine const callback = () => { isOnline = navigator.onLine; } window.addEventlistener(“online”, callback); window.addEventlistener(“offline”, callback); https://developer.mozilla.org/en-US/docs/Web/API/Navigator/onLine

Slide 11

Slide 11

02 Network Information API let userConnection = navigator.connection; // *.type (e.g. wifi, …) // *.effectiveType (e.g. 2g, 3g, …) // *.downlink // *.downlinkMax // *.rtt // *.saveData const callback = () => { userC onnection = navigator.connection; } navigator.connection .addEventListener(“change”, callb ack); https://developer.mozilla.org/en-US/docs/Web/API/Network_Information_API

Slide 12

Slide 12

02 Network Information API

Slide 13

Slide 13

03 Page Visibility API

Slide 14

Slide 14

03 Page Visibility API let isHidden = document.hidden; const callback = () => { isHidden = document.hidden; } document.addEventListener( “visibilitychange”, callback ); https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API

Slide 15

Slide 15

03 Page Visibility API

Slide 16

Slide 16

04 Battery Status API

Slide 17

Slide 17

04 Battery Status API const info = await navigator.getBattery(); // *.level // *.charging // *.chargingTime // *.dischargingTime info.addEventListener(“levelchange”, …); info.addEventListener(“chargingchange”, …); // … https://developer.mozilla.org/en-US/docs/Web/API/Battery_Status_API

Slide 18

Slide 18

04 Battery Status API

Slide 19

Slide 19

Enhance your components

Slide 20

Slide 20

05 Vibration API

Slide 21

Slide 21

05 Vibration API navigator.vibrate(duration); // Patterns // e.g. vibrate for 100ms with 50ms pauses navigator.vibrate([100, 50, 100, 50, 100]); // Stop long vibration or pattern navigate.vibrate(0); https://developer.mozilla.org/en-US/docs/Web/API/Vibration_API

Slide 22

Slide 22

05 Vibration API // SOS in Morse navigator.vibrate([ 100, 30, 100, 30, 100, 30, 200, 30, 200, 30, 200, 30, 100, 30, 100, 30, 100 ]); // Super Mario navigator.vibrate([ 125, 75, 125, 275, 200, 275, 125, 75, 125, 275, 200, 600, 200, 600 ]); // Star Wars navigator.vibrate([ 500, 110, 500, 110, 450, 110, 200, 110, 170, 40, 450, 110, 200, 110, 170, 40, 500 ]); https://gearside.com/custom-vibration-patterns-mobile-devices/

Slide 23

Slide 23

05 Vibration API , s e t a r b i v ! It r a e w Is

Slide 24

Slide 24

06 EyeDropper API

Slide 25

Slide 25

06 EyeDropper API const eyeDropper = new EyeDropper(); document.getElementById(“btn”) .addEventListener(“click”, () => { // Needs to be triggered by user action eyeDr opper.open() .then((result) => { // Returns the selected color // *.sRGBHex }) .catch((e) => { // Catches any errors, including // when the user cancels selection }); }); https://developer.mozilla.org/en-US/docs/Web/API/EyeDropper_API

Slide 26

Slide 26

06 EyeDropper API

Slide 27

Slide 27

Alomost as good as native

Slide 28

Slide 28

07 Web Share API

Slide 29

Slide 29

07 Web Share API const shareData = { title: “../NEW”, text: “Celebrate all things technology”, url: “https://slashnew.tech” files: [imageFile, videoFile] }; document.getElementById(“btn”) .addEventListener(“click”, () => { navigator.share(shareData) .catch((e) => { // Handle any errors }); }); https://developer.mozilla.org/en-US/docs/Web/API/Web_Share_API

Slide 30

Slide 30

07 Web Share API

Slide 31

Slide 31

08 Contact Picker API

Slide 32

Slide 32

08 Contact Picker API const props = [“name”, “email”, “tel”, “icon”]; const opts = { multiple: true }; const contacts = await navigator.contacts .select(props, opts); .catch((e) => { // Handle any errors }); https://developer.mozilla.org/en-US/docs/Web/API/Contact_Picker_API

Slide 33

Slide 33

08 Contact Picker API

Slide 34

Slide 34

09 Web OTP API

Slide 35

Slide 35

09 Web OTP API navigator.credentials .get({ otp: { transport: [“sms”] }, signal: ac.signal, }) .then((otp) => { // *.code }) .catch((e) => { // Handle any errors }); // Format of the SMS so it can be processed // Your verification code is 123456.\n\n // @app.stopme.io #123456 https://developer.mozilla.org/en-US/docs/Web/API/WebOTP_API

Slide 36

Slide 36

09 Web OTP API

Slide 37

Slide 37

09 Web OTP API

Slide 38

Slide 38

Honourable Mentions

Slide 39

Slide 39

Debugging Console Performance Memory

Slide 40

Slide 40

Debugging Console Performance Memory console.log(…); console.assert(…); console.count(…); console.countReset(…); console.dir(…); console.table(…); console.group(…); console.groupCollapsed(…); console.groupEnd(…); console.time(…); console.timeEnd(…); console.trace(…); console.clear(); https://developer.mozilla.org/en-US/docs/Web/API/Console_API

Slide 41

Slide 41

Debugging const time = performance.now(); performance.mark(“start”); performance.mark(“end”, { detail: { … } }); performance.measure(“login”, “start”, “end”); Console Performance Memory const observer = new PerformanceObserver((list, obj) => { list.getEntries().forEach((entry) => { // *.name // *.startTime // *.duration // *.detail }); }); observ er.observe({ type: “res ource” }); https://developer.mozilla.org/en-US/docs/Web/API/Performance

Slide 42

Slide 42

Debugging Console const memory = navigator.deviceMemory; // Device has at least ${memory}GiB of RAM const memorySample = await performance .measureUserAgentSpecificMemory(); // *.bytes // *.breakdown[].bytes // *.breakdown[].attribution // *.breakdown[].types Performance Memory https://developer.mozilla.org/en-US/docs/Web/API/Device_Memory_API

Slide 43

Slide 43

Auth but better Credentials API AUthn API

Slide 44

Slide 44

Auth but better const cred = new PasswordCredential({ id, password, name }); // Store credentials await navigator.credentials.store(cred); Credentials API AUthn API // Get stored credentials const user = await navigator.credentials.get(); // Prevent automatic login when user signs out await navigator .credentials .preventSilentAccess(); https://developer.mozilla.org/en-US/docs/Web/API/Credential_Management_API

Slide 45

Slide 45

Auth but better Credentials API AUthn API // Create credentials object on the client // using challenge generated on the server const registerCredential = await navigator.credentials.create({ publicKey }); // Credentials are stored with the user // identity are sent back and stored on the // server // Authenticate again using server challenge const authCredential = await navigator.credentials.get({ publicKey }); // Use stored public key to verify validity // of auth crendentials https://developer.mozilla.org/en-US/docs/Web/API/Web_Authentication_API

Slide 46

Slide 46

https://webauthn.io/ Auth but better Credentials API AUthn API

Slide 47

Slide 47

The Next GENeration INTL API Temporal* Navigation API

Slide 48

Slide 48

The Next generation INTL API Temporal* Navigation API const o ptions = { dateStyle: “full”, timeSt yle: “long”, timeZone: “ Australia/Sydney” }); new Intl.D ateTimeFormat(“en-US”, options) .format(date); // Friday, December 2, 2022 at 12:21:40 PM // GMT+11 // Relative time const fmt = new Intl.Rela tiveTimeFormat( “en “, { st yle: “narrow” } ); fmt.format(3, “day”); // in 3 days fmt.for mat(-2, “year”); // 2 years ago https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl

Slide 49

Slide 49

The Next generation INTL API Temporal* const au = new Intl.NumberFormat(“en-AU”); au.format(123_456.79); // 123,456.79 const de = new Intl.NumberFormat(“de-DE”); de.format(123_456.79); // 123.456,79 const fmt = new Int l.NumberFormat( “de- DE”, { style: “currency”, currency: “EUR” } ); fmt.f ormat(123_456.79) // 123.456,79 € Navigation API https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl

Slide 50

Slide 50

The Next generation INTL API Temporal* Navigation API // Get exact current system time Temporal.Now.instant(); // Get time zone Temporal.Now.timeZoneId(); // Useful utilities const date = Temporal.PlainDate.from(dateStr); // *.year // *.inLeapYear // *.toString() // … // Manipulate time date.add({ hours: 1 }); https://tc39.es/proposal-temporal/docs/

Slide 51

Slide 51

The Next generation INTL API Temporal* Navigation API // Promises for the win (finally!) await navigation.reload({ info, state }); // Navigate around await navigation.navigate(url, options); await navigation.back(options); await navigation.forward(options); await navigation.traverseTo(key, options); // Events navigation .addEventListener(“currententrychange”); .addEventListener(“navigate”); .addEventListener(“navigatesuccess”); .addEventListener(“navigateerror”); https://developer.mozilla.org/en-US/docs/Web/API/Navigation_API

Slide 52

Slide 52

The Next generation URL Patterns Popover const p = new URLPattern({ pathname: “/foo” }); p.test(“https://example.com/books”)); // true const p = new URLPattern({ pathname: “/books/:id” }); const match = p.exec(“https://example.com/books/123”); // *.pathname.groups.id = 123 const p = new URLPattern( “/books/:id(\d+)”, “https://example.com” ); View Transition https://developer.mozilla.org/en-US/docs/Web/API/URL_Pattern_API

Slide 53

Slide 53

The Next generation URL Patterns Popover <button popovertarget=”mypopover”> Toggle the popover </button> <div id=”mypopover” popover> Popover content </div> document.addEventListener(“keydown”, (e) => { if (e.key === “h”) { mypopover.togglePopover(); } }); View Transition https://developer.mozilla.org/en-US/docs/Web/API/Popover_API

Slide 54

Slide 54

The Next generation function updateView(e) { e.preventDefault(); const details = e.target.closest(“details”); if (!document.startViewTransition) { // Fallback for older browsers details.toggleAttribute(“open”) } URL Patterns Popover document.startViewTransition(() => details.toggleAttribute(“open”) ); } View Transition https://developer.mozilla.org/en-US/docs/Web/API/View_Transitions_API

Slide 55

Slide 55

Thanks! @jburr90 / julian burr https://www.julianburr.de/ web-directions-code-2024slides.pdf