Pava
I code and teach JavaScript
Software Engineer @TapWater
Use the platform means choosing native features/APIs versus 3rd party libraries.
Behind all the APIs we use, are groups of people whose job is to push the Web forward.
Time
Features
3rd party libraries
The platform
Features that only the platform can implement
📦 No extra library
🚀 Faster load times
Less JS to download
Less opportunities for bugs
Less code in our app
📈 Higher chance of devs knowing the standard APIs
Easier to understand, use or refactor the code
1. Start with libraries. Don't wanna get old waiting 👴🏻
2. Continue with native features when they're available
3. Maybe refactor if I have time
Most of the images on the web are downloaded, decoded and rendered only never to be seen, as [...] the user never scrolled that far. - Yoav Weiss
In my first ever paid-project in 2018, I used lazysizes to lazy load images.
<!DOCTYPE html>
<html lang="en">
<head>
<title>Lazy Loading</title>
<script src="lazysizes.min.js"></script>
</head>
<body>
<img data-src="image.jpg" class="lazyload" />
</body>
</html>
It is downloaded more than 250k times per week
However, now we have native lazy loading right into the platform 🎉
<!DOCTYPE html>
<html lang="en">
<head>
<title>Lazy Loading</title>
</head>
<body>
<img src="image.jpg" loading="lazy" />
</body>
</html>
<body>
<button
class="btn"
data-clipboard-text="Text to copy to clipboard">
Click me to copy!
</button>
<script>
let clipboard = new ClipboardJS('.btn');
clipboard.on('success', function (e) {
e.clearSelection();
// Now I have it copied to the clipboard
});
clipboard.on('error', function (e) {
// Oops. It failed...
});
</script>
</body>
For years I've been using Clipboard JS for this.
function copyToClipboard(text) {
try {
await navigator.clipboard.writeText(text);
} catch (err) {
console.log("Oops, something went wrong.", err);
}
}
Now we can just use the Native Clipboard API!
const req = new XMLHttpRequest();
req.addEventListener("load", onLoad);
req.addEventListener("error", onError);
req.open("GET", "http://www.example.org/example.txt");
req.setRequestHeader("content-type", "application/json");
req.send();
function onLoad() {
console.log(req.responseText);
}
function onError(err) {
console.log("Something failed", err);
}
When I started programming we had to use the XMLHttpRequest to make AJAX calls...
try {
const response = await fetch('https://example.com/movies');
const jsonResponse = await response.json();
} catch (err) {
// Handle error
}
Luckily I haven't written that in maaaany years, because we have the native fetch API.
try {
const response = await fetch('https://example.com/movies', {
headers: new Headers({
'content-type': 'application/json',
}),
method: 'POST',
body: JSON.stringify(body),
});
const jsonResponse = await response.json();
} catch (err) {
// Handle error
}
This is a POST Request with custom Headers:
pune exemplu cu Axios, cand ar trebui folosit
import axios from 'axios';
try {
const jsonResponse = await axios.post(
'https://example.com/movies',
body,
{
'content-type': 'application/json'
}
);
} catch (err) {
// Handle error
}
Date
📅 30.10.2022, 09:12
number
💰 2.000,00 RON
let today = new Date();
let roDateFormatter = Intl.DateTimeFormat('ro-RO');
let enDateFormatter = Intl.DateTimeFormat('en-US');
console.log(roDateFormatter.format(today));
// 12.11.2022
console.log(enDateFormatter.format(today));
// 11/12/2022
The Intl API is great for serializing dates...
let salary = 5000;
let roRONFormatter = Intl.NumberFormat('ro-RO', {
style: 'currency',
currency: 'RON'
});
let roUSDFormatter = Intl.NumberFormat('ro-RO', {
style: 'currency',
currency: 'USD'
});
let usRONFormatter = Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'RON'
});
let usUSDFormatter = Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD'
});
console.log(roRONFormatter.format(salary));
// 5.000,00 RON
console.log(roUSDFormatter.format(salary));
// 5.000,00 USD
console.log(usRONFormatter.format(salary));
// RON 5,000.00
console.log(usUSDFormatter.format(salary));
// $5,000.00
... and Currency.
import { startOfWeek, endOfWeek } from 'date-fns';
getWeekInterval(new Date());
// 7 - 13 November
function getWeekInterval(date) {
let month = Intl.DateTimeFormat('en-US', {
month: 'long'
}).format(new Date());
let startDay = startOfWeek(dateToShow);
let endDay = endOfWeek(dateToShow);
return `${startDay.getDate()} ${month}` +
`- ${endDay.getDate()} ${month}`;
}
However, for more advanced stuff, we may still need to use libraries like date-fns.
What if we could built this with native HTML elements, and NO JavaScript?? 🤯🤯🤯
Meet the <details> element
<details>
<summary> Title </summary>
<div> Content </div>
</details>
And here's the HTML code:
<details>
<summary>
<span class="number">01</span>
<span class="question">Where are the stores located?</span>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"
class="icon">
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 8.25l-7.5 7.5-7.5-7.5" />
</svg>
</summary>
<div class="accordion-content">
<p>
Lorem, ipsum dolor sit amet consectetur adipisicing elit. Dolorem
fuga praesentium nisi molestiae illo dolorum unde aliquid tenetur,
repellendus ut sit tempora necessitatibus, odit, dolor sequi
laudantium soluta nesciunt atque!
</p>
<ul>
<li>Lorem ipsum dolor sit amet consectetur adipisicing.</li>
<li>Lorem ipsum dolor sit amet consectetur adipisicing.</li>
<li>Lorem ipsum dolor sit amet consectetur adipisicing.</li>
<li>Lorem ipsum dolor sit amet consectetur adipisicing.</li>
<li>Lorem ipsum dolor sit amet consectetur adipisicing.</li>
</ul>
</div>
</details>
<!DOCTYPE html>
<html lang="en">
<head>
<title>Form parsing</title>
</head>
<body>
<form>
<input type="text" name="username" />
<input type="number" name="age" />
<button type="submit"> Submit </button>
</form>
<script>
const form = document.querySelector("form");
form.addEventListener("submit", (event) => {
event.preventDefault();
const formData = new FormData(event.currentTarget);
console.log(Object.fromEntries(formData));
// { username: "bob", age: "27" }
});
</script>
</body>
</html>
For very basic forms we can use the native APIs to read and process the data.
Even when using libraries/frameworks like React, I sometime prefer the native approach for simplicity.
Not Any More! 🎉
<!DOCTYPE html>
<html lang="en">
<head>
<title>Form parsing</title>
</head>
<body>
<dialog open>
<p> Finally, a native dialog! </p>
<button> Great! </button>
</dialog>
</body>
</html>
Open it with show() or showModal()
let dialog = document.querySelector('dialog');
// We can still interact with the rest of the page
dialog.show();
// We cannot interact with the rest of the page
dialog.showModal();
Style the backdrop:
dialog::backdrop {
background: linear-gradient(#e6646580, #9198e580);
}
Close when clicking the backdrop:
const dialogEl = document.querySelector("dialog");
dialogEl.addEventListener('click', maybeCloseDialog);
function maybeCloseDialog(e) {
if (e.target.tagName === 'DIALOG') {
dialogEl.close();
}
}
<dialog>
<div class="dialog-content">
<p> This is a simple dialog </p>
<button type="button"> Close </button>
</div>
</dialog>
Not the best but I'll take it...
class CreditCard {
private number;
constructor() {
this.number = '...';
}
private getNumber() {
return this.number;
}
getInfo() {
const lastFour = this.getNumber().slice(-4);
return `Last four numbers: ${lastFour}`;
}
}
We've been using TypeScript for many years to declare private properties.
Now we finally got native support!
class CreditCard {
// private variable
#number;
constructor() {
this.#number = '...';
}
// private function
#getNumber() {
return this.#number;
}
getInfo() {
const lastFour = this.#getNumber().slice(-4);
return `Last four numbers: ${lastFour}`;
}
}
We can start writing code using the new syntax!
I already started doing this, and slowly migrating old code when I get some extra "free" hours. 🙌
Probably the feature I'm most excited about!
And here's how to use them:
.parent {
container-type: inline-size;
}
@container (max-width: 400px) {
// ...
}
@container (min-width: 400px) and (max-width: 700px) {
// ...
}
@container (min-width: 700px) {
// ...
}
Not full support but getting there. Looking at you Firefox 👀
<tabs>
<tab title="Home">
<!-- ... -->
</tab>
<tab title="Settings">
<!-- ... -->
</tab>
</tabs>
We were supposed to get an easy way to build custom components, for example tabs:
And replace all the frameworks:
Instead, we got this:
By Pava
The browser is pretty powerful, and we can do a lot of things natively, without using libraries. What are some of these things and why start with the platform first?