This is HTML version of Web Development tailored for 2024.

PDF Version also available

whoami === andrzejfricze

fricze.com/webdev24

Web Development tailored for 2024

Web Development tailored for 2024

or: Not your dads Web Platform

Web Development tailored for 2024

or: Not your dads Web Platform

or: Not main Web Platform tbh, because a lot has changed since I started…

Native features

  • are generally, faster than libraries and frameworks
  • will be available even when your favorite framework changes
  • make debugging easier, because that's the language that browsers speak
  • sometimes are just magic that cannot be polyfilled in your favorite framework!

This is a speedrun. I won't teach you everything, but you'll know what to look for

buckle up kiddo 🤠

Disclaimer

A lot of examples are not main, but are taken from MDN, web.dev, codepen.io, or similar, publicly available sources

No more "undefined is not a function"

Safe null checks in JavaScript

Nullish coalescing operator 1

let number = 0 || 1;
// number === 1
number = 0 ?? 1;
// number === 0

let string = '' || 'string';
// string === 'string'
string = '' ?? 'string';
// string === ''

Optional chaining 1

const ArticleView = (props) => {
    const value = props.article.value;
    // Uncaught TypeError: Cannot read properties of undefined (reading 'value')

    const maybeValue = props.article?.value;
    // maybeValue === undefined
    …
};

Native async possibilities ⌛️

Better control over Promises and Iterables

Collect the results of all given promises. Even those that threw an error

Promise.allSettled 1

// OLD
Promise.all([Promise.resolve(10), Promise.resolve(20)])
    === [10, 20]
// OLD
Promise.all([Promise.resolve(10), Promise.reject(20)])
    === Promise {<rejected>: 20}

// NEW 🔥
Promise.allSettled([Promise.resolve(10), Promise.reject(20)])
    === [
      {status: 'fulfilled', value: 10},
      {status: 'rejected', reason: 20},
    ]

From event-based to Promise-based APIs

Promise.withResolvers 1

const getRequestPromise = () => {
    const {
      promise, resolve, reject
    } = Promise.withResolvers();

    asyncRequest(config, response => {
      const buffer = [];
      response.on('data', data => buffer.push(data));
      response.on('end', () => resolve(buffer));
      response.on('error', reason => reject(reason));
    });

    return promise;
}

Array.fromAsync for consuming asynchronous iterables 1

const asyncIterable = (async function* () {
  for (let i = 0; i < 5; i++) {
    await new Promise((resolve) => setTimeout(
        resolve, 10 * i
    ));
    yield i;
  }
})();

await Array.fromAsync(asyncIterable) === [0, 1, 2, 3, 4]

The end of lodash? 🤯

New methods to manipulate Arrays and Objects

Easier access to array elements arr.at(), arr.findLast() 1

const arr = [5, 12, 50, 130, 44];
arr.at(3) === arr[3] === 130;
arr.at(-2) === arr[4] === 130;

arr.find((element) => element > 45)
    === 50

arr.findLast((element) => element > 45)
    === 130

Safe state changes in React with…

immutable arrays methods 1

All those methods return new array instead of mutating

Array.prototype.toSorted()
Array.prototype.toReversed()
Array.prototype.toSpliced()
Array.prototype.with()

Safe React state update

const [posts, setPosts] = useState([]);

setPosts(posts => posts.with(
    3,
    {...posts[3],
    "title": "Updated post title"})
);

Group arrays into Objects or Maps 1

Object.groupBy()
Map.groupBy()

Native EventTarget constructor

.addEventListener() on your own objects

class Counter extends EventTarget {
  constructor(initialValue = 0) {
    super();
    this.value = initialValue;
  }

  #emitChangeEvent() {
    this.dispatchEvent(new CustomEvent("valuechange", { detail: this.value }));
  }

  increment() {
    this.value++;
    this.#emitChangeEvent();
  }

  decrement() {
    this.value--;
    this.#emitChangeEvent();
  }
}

const counter = new Counter(0);

counter.addEventListener("valuechange", (event) => {
  document.querySelector("#currentValue").innerText = event.detail;
});

Can I use those features? What about browsers that don't support them?

@babel/preset-env 🫡

Better responsive design

Dynamic viewport units 1

height: 45dvh

No more margin problems with

CSS Gap for Flexbox and Grid 1

.flex-gap {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 12px;
}
.grid-gap {
  display: grid;
  // gap: 12px 20px;
  column-gap: 12px;
  row-gap: 20px;
}

Interop 2023

Container Queries and Container Units

Components responsive in relation to container not whole window

One component adjusting to given role and position

https://codepen.io/wuuuuuuuuut/pen/RwOxVQe

also…

Container queries might be are an alternative to listening to element resize

https://codepen.io/chriscoyier/pen/jOeBzNN

Interop 2023

Subgrid. Full control over your layout

Want to support older browsers?

Remove container from DOM tree with display: contents to imitate subgrid

Supported since 2018

https://css-tricks.com/get-ready-for-display-contents/

New ways to optimize performance

Part of new containment spec. Partial implementation in Firefox and Safari

Control rendering with content-visibility

All browsers since 2022

contain: strict

for isolating rendering layers

New animation APIs. More fun designs

Interop 2023

CSS Motion Path for creating exact animation paths

CSS Scroll Behavior for smooth scrolling

https://codepen.io/wuuuuuuuuut/pen/BaEJJYY

CSS syntax improvements

:is(), :where()

for shorter CSS selectors 1

Before :is()

/* Level 0 */
h1 {
  font-size: 30px;
}

/* Level 1 */
section h1,
article h1,
aside h1,
nav h1 {
  font-size: 25px;
}

/* Level 2 */
section section h1,
section article h1,
section aside h1,
section nav h1,
article section h1,
article article h1,
article aside h1,
article nav h1

After :is() 🔥

/* Level 0 */
h1 {
  font-size: 30px;
}
/* Level 1 */
:is(section, article, aside, nav) h1 {
  font-size: 25px;
}
/* Level 2 */
:is(section, article, aside, nav) :is(section, article, aside, nav) h1 {
  font-size: 20px;
}

Interop 2023

:has() – real parent selector! 1

label:has(input:invalid) {
    color: red;
}

Available since 2022. Polyfill available

Control CSS cascading with @layer 1 2 3

Works with @import!

@import url(headings.css) layer(default);
@import url(links.css) layer(default);
@import url(links-dimmed.css) layer(dimmed);

@layer default {
  audio[controls] {
    display: block;
  }
}

Interop 2024

CSS Nesting! 1

// that's native CSS! 🥳
input {
  /* styles for input not in a label  */
  border: tomato 2px solid;
}
label {
  /* styles for label */
  font-family: system-ui;
  font-size: 1.25rem;
  & input {
    /* styles for input in a label  */
    border: blue 2px dashed;
  }
}

Easier declarations, easier animations

Individual transform properties 1

// old transform property
.logo {
    transform: rotate(45deg) scale(2) translate(40px, 0);
}

// new, individual properties
.logo {
    rotate: 45deg;
    scale: 2;
    translate: 40px, 0;
}

Better web typography

Interop 2024

text-wrap: balance

unbalanced: https://codepen.io/wuuuuuuuuut/pen/RwOxVQe

vs balanced: https://codepen.io/wuuuuuuuuut/pen/QWPaMWQ

No more :before and weird borders

text-decoration magic (since 2020)

and lh unit for vertical rhythm (2023)

https://codepen.io/wuuuuuuuuut/pen/yLrpoaR

and text-emphasis!

(Because why not?!)

https://codepen.io/wuuuuuuuuut/pen/MWRrvbz

Available since 2021

Build coherent form controls with

accent-color

https://codepen.io/web-dot-dev/pen/PomBZdy

HTML features you might not be using

Lazy loaded images for better LCP and 1

.webp format for faster loading 2

<img src="goofy.webp" loading="lazy" … />

Widely available since 2019…

<datalist> - predefined autocomplete for forms 1

Widely available since 2022

Native modals with

<dialog> 1 and [inert] 2

What's coming to JS?

More functional features ❤️

TC39 Stage 2

Pipe operator – easy function calls 📞 1

From this mess…

console.log(
  chalk.dim(
    `$ ${Object.keys(envars)
      .map(envar =>
        `${envar}=${envars[envar]}`)
      .join(' ')
    }`,
    'node',
    args.join(' ')));

to this 🥳

Object.keys(envars)
  .map(envar =>
    `${envar}=${envars[envar]}`)
  .join(' ')
  |> `$ ${%}`
  |> chalk.dim(
    %, 'node', args.join(' '))
  |> console.log(%);

TC39 Stage 2

Records and Tuples – immutable data structures in JavaScript, with cheap equality checks 1

const proposal = #{
  id: 1234,
  title: "Record & Tuple proposal",
  contents: `...`,
  // tuples are primitive types so you can put them in records:
  keywords: #["ecma", "tc39", "proposal", "record", "tuple"],
};

// Accessing keys like you would with objects!
proposal.title === "Record & Tuple proposal"
proposal.keywords[1] === "tc39"

// Spread like objects!
const proposal2 = #{
  ...proposal,
  title: "Stage 2: Record & Tuple",
};
proposal2.title === "Stage 2: Record & Tuple"
proposal2.keywords[1] === "tc39"

// Object functions work on Records:
Object.keys(proposal) === ["contents", "id", "keywords", "title"]

With immutable data structures React might, finally, be fast!

Future of CSS? Animating everything!

Interop 2024 – almost there!

Entry / exit animations

https://developer.chrome.com/blog/entry-exit-animations/

I dislike the fact that you still need to wait for animations to finish before you remove element from DOM. But hey, it's opportunity to use new .getAnimations() API

Promise.all(
  elem
    .getAnimations({ subtree: true })
    .map((animation) => animation.finished),
).then(() => elem.remove());

Firefox - behind flag

Safari - no implementation

Polyfill available

Scroll Driven Animations

https://scroll-driven-animations.style/

https://github.com/flackr/scroll-timeline

Firefox, Safari - no implementation. Can't polyfill 🤷🏼‍♂️

View Transitions

Animated transitions between separate DOM elements 🤩

Future of DOM API

DOM Parts API! 🔥 1

No more JSX?!

<template>
  <section>
    <h1 id="name">{{}}</h1>
    Email: <a id="link" href="{{}}">{{}}</a>
  </section>
</template>

{{}} is a reference to a specific place in DOM tree

Quick update without traversing the tree

<template>
  <section>
    <h1 id="name">{{}}</h1>
    Email: <a id="link" href="{{}}">{{}}</a>
  </section>
</template>

HTML Template Instantiation – Angular templates in browser

https://github.com/WICG/webcomponents/blob/gh-pages/proposals/Template-Instantiation.md

Thanks!

a.fricze@pm.me / fricze.com

Chat with me about:

  1. New Web Platform features
  2. Presentations, meetups, conferences, workshops
  3. Jotai and RTK-Query
  4. Music production (YT: 23carats beats)
  5. Gym
  6. „Certified Web Platform Inspector” t-shirts (fricze.com/merch)