[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"verticals":3,"tag-webdev-1":32,"tags-dev":292},[4,20],{"id":5,"slug":6,"name":7,"tagline":8,"description":9,"accentFrom":10,"accentTo":11,"icon":12,"defaultLocale":13,"locales":14,"features":16,"position":19},"019fe637-3d33-714b-b57f-23e163ffca0c","dev","Web Development","Build. Learn. Ship.","Practical courses, engineering-grade articles and open-source tools for people who ship.","violet-500","cyan-400","◇","en",[13,15],"fa",{"courses":17,"paths":17,"articles":17,"exams":18,"flashcards":18,"packages":17,"community":17,"certificates":17,"teams":17,"commerce":17},true,false,0,{"id":21,"slug":22,"name":23,"tagline":24,"description":25,"accentFrom":26,"accentTo":10,"icon":27,"defaultLocale":13,"locales":28,"features":30,"position":31},"019fe637-3dc2-754c-8657-0f175bfee7c6","lang","Languages","Learn a language the way you learn a codebase.","Structured paths, listening drills and spaced repetition that actually sticks.","amber-400","⌘",[13,15,29],"es",{"courses":18,"paths":18,"articles":17,"exams":18,"flashcards":17,"packages":18,"community":17,"certificates":17,"teams":18,"commerce":18},2,{"items":33,"meta":289},[34,68,88,107,129,148,168,188,210,230,248,271],{"id":35,"slug":36,"title":37,"subtitle":38,"excerpt":39,"coverUrl":40,"locale":13,"readingMinutes":41,"publishedAt":42,"viewCount":43,"likeCount":19,"commentCount":19,"author":44,"vertical":49,"topic":50,"tags":53,"_count":65,"playground":67,"hasQuiz":17,"hasPlayground":17},"019ff19b-f68d-77ea-9a2c-70e14c5c7a05","mutation-observer-dom-change-detection","You're polling setInterval to detect DOM changes. `MutationObserver` fires when they happen.",null,"Watching for DOM mutations with setInterval or custom event dispatch is fragile and imprecise. The MutationObserver API delivers a callback exactly when attributes, text content, or child elements change — with full control over which types of mutations you watch.","\u002Fmedia\u002Fcovers\u002Fmutation-observer-dom-change-detection.png",4,"2026-08-11T15:48:01.781Z",223,{"id":45,"name":46,"username":47,"avatarUrl":38,"headline":48},"019fe637-3c25-7088-9034-39c9f15dc3c8","Parsa Jiravand","parsa","Frontend engineer · building bestpractic",{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":51,"name":52},"javascript","JavaScript",[54,56,59,62],{"slug":51,"name":55,"color":38},"Javascript",{"slug":57,"name":58,"color":38},"webdev","Webdev",{"slug":60,"name":61,"color":38},"frontend","Frontend",{"slug":63,"name":64,"color":38},"dom","Dom",{"assessments":66},1,{"slug":36},{"id":69,"slug":70,"title":71,"subtitle":38,"excerpt":72,"coverUrl":73,"locale":13,"readingMinutes":41,"publishedAt":74,"viewCount":75,"likeCount":19,"commentCount":19,"author":76,"vertical":77,"topic":78,"tags":79,"_count":86,"playground":87,"hasQuiz":17,"hasPlayground":17},"019ff19b-f5b3-7569-8cc8-22b1136aa9b2","compressionstream-native-gzip","You're importing pako to gzip data. `CompressionStream` does it natively.","pako is one of npm's most downloaded packages — pulled in by thousands of projects to compress data before storing or sending it. CompressionStream and DecompressionStream do the same job natively, in any modern browser and Node.js 18+, with no dependencies and native C-speed execution.","\u002Fmedia\u002Fcovers\u002Fcompressionstream-native-gzip.png","2026-08-10T07:49:27.000Z",103,{"id":45,"name":46,"username":47,"avatarUrl":38,"headline":48},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":51,"name":52},[80,81,82,83],{"slug":51,"name":55,"color":38},{"slug":57,"name":58,"color":38},{"slug":60,"name":61,"color":38},{"slug":84,"name":85,"color":38},"performance","Performance",{"assessments":66},{"slug":70},{"id":89,"slug":90,"title":91,"subtitle":38,"excerpt":92,"coverUrl":93,"locale":13,"readingMinutes":41,"publishedAt":94,"viewCount":75,"likeCount":19,"commentCount":19,"author":95,"vertical":96,"topic":97,"tags":98,"_count":105,"playground":106,"hasQuiz":17,"hasPlayground":17},"019fe660-fcbe-745e-a443-5ae33ac10aaf","broadcast-channel-cross-tab-messaging","Stop using the localStorage hack to sync browser tabs. BroadcastChannel does it natively.","Syncing state across browser tabs with localStorage events is a widely-used trick that requires JSON.stringify, event filtering, and careful cleanup. The Broadcast Channel API delivers messages between tabs directly, with none of the side effects.","\u002Fmedia\u002Fcovers\u002Fbroadcast-channel-cross-tab-messaging.png","2026-08-09T07:02:41.629Z",{"id":45,"name":46,"username":47,"avatarUrl":38,"headline":48},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":51,"name":52},[99,100,101,102],{"slug":51,"name":55,"color":38},{"slug":57,"name":58,"color":38},{"slug":60,"name":61,"color":38},{"slug":103,"name":104,"color":38},"apis","Apis",{"assessments":66},{"slug":90},{"id":108,"slug":109,"title":110,"subtitle":38,"excerpt":111,"coverUrl":112,"locale":13,"readingMinutes":113,"publishedAt":114,"viewCount":115,"likeCount":19,"commentCount":19,"author":116,"vertical":117,"topic":118,"tags":121,"_count":127,"playground":128,"hasQuiz":17,"hasPlayground":17},"019ff19b-f388-73f8-aa5b-93d73337d6fd","dialog-element-native-modal","You built your modal with a `\u003Cdiv>` and a focus trap library. The native `\u003Cdialog>` does all of that.","The `\u003Cdialog>` element ships with focus trapping, Escape-to-close, backdrop rendering, and correct ARIA semantics — no library, no boilerplate. It's been Baseline since 2022.","\u002Fmedia\u002Fcovers\u002Fdialog-element-native-modal.png",5,"2026-08-08T07:00:10.810Z",99,{"id":45,"name":46,"username":47,"avatarUrl":38,"headline":48},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":119,"name":120},"html","HTML",[122,124,125,126],{"slug":119,"name":123,"color":38},"Html",{"slug":57,"name":58,"color":38},{"slug":60,"name":61,"color":38},{"slug":51,"name":55,"color":38},{"assessments":66},{"slug":109},{"id":130,"slug":131,"title":132,"subtitle":38,"excerpt":133,"coverUrl":134,"locale":13,"readingMinutes":135,"publishedAt":136,"viewCount":137,"likeCount":19,"commentCount":19,"author":138,"vertical":139,"topic":140,"tags":141,"_count":146,"playground":147,"hasQuiz":17,"hasPlayground":17},"019fe660-f552-73c8-9f52-d036e672c053","crypto-randomuuid-native-uuid","Stop importing `uuid`. `crypto.randomUUID()` has been native since 2021.","The `uuid` package is downloaded hundreds of millions of times a week. Most installs exist to call uuid\u002Fv4 — exactly what `crypto.randomUUID()` does natively, with no import, no bundle cost, and guaranteed cryptographic randomness.","\u002Fmedia\u002Fcovers\u002Fcrypto-randomuuid-native-uuid.png",3,"2026-08-08T07:00:09.988Z",98,{"id":45,"name":46,"username":47,"avatarUrl":38,"headline":48},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":51,"name":52},[142,143,144,145],{"slug":51,"name":55,"color":38},{"slug":57,"name":58,"color":38},{"slug":60,"name":61,"color":38},{"slug":84,"name":85,"color":38},{"assessments":66},{"slug":131},{"id":149,"slug":150,"title":151,"subtitle":38,"excerpt":152,"coverUrl":153,"locale":13,"readingMinutes":41,"publishedAt":154,"viewCount":155,"likeCount":19,"commentCount":19,"author":156,"vertical":157,"topic":158,"tags":159,"_count":166,"playground":167,"hasQuiz":17,"hasPlayground":17},"019fe660-edbb-714e-b0e8-8488ccbb6940","intl-relativetimeformat-relative-dates","You're installing date-fns for 'X hours ago'. `Intl.RelativeTimeFormat` does it natively.","Most apps display relative timestamps — '3 minutes ago', 'last week'. Developers still reach for date-fns or moment for this. The Intl.RelativeTimeFormat API handles it natively, with full locale support and zero dependencies.","\u002Fmedia\u002Fcovers\u002Fintl-relativetimeformat-relative-dates.png","2026-08-07T07:22:54.352Z",30,{"id":45,"name":46,"username":47,"avatarUrl":38,"headline":48},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":51,"name":52},[160,161,162,163],{"slug":51,"name":55,"color":38},{"slug":57,"name":58,"color":38},{"slug":60,"name":61,"color":38},{"slug":164,"name":165,"color":38},"intl","Intl",{"assessments":66},{"slug":150},{"id":169,"slug":170,"title":171,"subtitle":38,"excerpt":172,"coverUrl":173,"locale":13,"readingMinutes":41,"publishedAt":174,"viewCount":175,"likeCount":19,"commentCount":19,"author":176,"vertical":177,"topic":178,"tags":179,"_count":186,"playground":187,"hasQuiz":17,"hasPlayground":17},"019ff19b-f047-748a-800d-00912a4d95c9","object-hasown-safe-property-check","You use `obj.hasOwnProperty(key)` to check property ownership. It can silently fail. `Object.hasOwn()` is the safe replacement.","Two real cases where `obj.hasOwnProperty(key)` throws or returns wrong results — and why `Object.hasOwn(obj, key)` is the ES2022 fix that ESLint's `no-prototype-builtins` rule has been nudging you toward for years.","\u002Fmedia\u002Fcovers\u002Fobject-hasown-safe-property-check.png","2026-08-06T08:44:20.722Z",26,{"id":45,"name":46,"username":47,"avatarUrl":38,"headline":48},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":51,"name":52},[180,181,182,183],{"slug":51,"name":55,"color":38},{"slug":57,"name":58,"color":38},{"slug":60,"name":61,"color":38},{"slug":184,"name":185,"color":38},"typescript","Typescript",{"assessments":66},{"slug":170},{"id":189,"slug":190,"title":191,"subtitle":38,"excerpt":192,"coverUrl":193,"locale":13,"readingMinutes":41,"publishedAt":194,"viewCount":175,"likeCount":19,"commentCount":19,"author":195,"vertical":196,"topic":197,"tags":200,"_count":208,"playground":209,"hasQuiz":17,"hasPlayground":17},"019fe660-e5d0-756a-9ae2-20c6ff4c2f48","css-style-queries-react-to-custom-properties","Container queries can check more than size — style queries let components read custom property values","Size queries react to container width. Style queries react to CSS custom property values on a container ancestor — enabling component-level theming and variant switching in pure CSS, no JavaScript involved.","\u002Fmedia\u002Fcovers\u002Fcss-style-queries-react-to-custom-properties.png","2026-08-06T08:44:20.136Z",{"id":45,"name":46,"username":47,"avatarUrl":38,"headline":48},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":198,"name":199},"css","CSS",[201,203,204,205],{"slug":198,"name":202,"color":38},"Css",{"slug":57,"name":58,"color":38},{"slug":60,"name":61,"color":38},{"slug":206,"name":207,"color":38},"components","Components",{"assessments":66},{"slug":190},{"id":211,"slug":212,"title":213,"subtitle":38,"excerpt":214,"coverUrl":215,"locale":13,"readingMinutes":41,"publishedAt":216,"viewCount":217,"likeCount":19,"commentCount":19,"author":218,"vertical":219,"topic":220,"tags":221,"_count":228,"playground":229,"hasQuiz":17,"hasPlayground":17},"019fe660-de51-759d-935f-dbda9e7e38b5","array-from-async-async-iterable","You're collecting async iterable results with a for-await loop. `Array.fromAsync` does it in one call.","A for-await loop that pushes into an array, or the `await Promise.all([...asyncIterable])` workaround that silently fails — `Array.fromAsync` replaces both with a single awaited call. It's Baseline 2024.","\u002Fmedia\u002Fcovers\u002Farray-from-async-async-iterable.png","2026-08-05T08:42:50.920Z",278,{"id":45,"name":46,"username":47,"avatarUrl":38,"headline":48},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":51,"name":52},[222,223,224,225],{"slug":51,"name":55,"color":38},{"slug":57,"name":58,"color":38},{"slug":60,"name":61,"color":38},{"slug":226,"name":227,"color":38},"async","Async",{"assessments":66},{"slug":212},{"id":231,"slug":232,"title":233,"subtitle":38,"excerpt":234,"coverUrl":235,"locale":13,"readingMinutes":113,"publishedAt":236,"viewCount":237,"likeCount":19,"commentCount":19,"author":238,"vertical":239,"topic":240,"tags":241,"_count":246,"playground":247,"hasQuiz":17,"hasPlayground":17},"019fe660-d6d5-7099-89bb-af60e48fcb28","content-visibility-skip-offscreen-rendering","Your browser renders everything, even what you can't see — `content-visibility: auto` fixes that","Browsers lay out and paint the entire page on load, including the 80% below the fold. `content-visibility: auto` tells the browser to skip that work for off-screen elements — and it's Baseline 2024.","\u002Fmedia\u002Fcovers\u002Fcontent-visibility-skip-offscreen-rendering.png","2026-08-04T08:44:59.227Z",254,{"id":45,"name":46,"username":47,"avatarUrl":38,"headline":48},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":198,"name":199},[242,243,244,245],{"slug":198,"name":202,"color":38},{"slug":57,"name":58,"color":38},{"slug":84,"name":85,"color":38},{"slug":60,"name":61,"color":38},{"assessments":66},{"slug":232},{"id":249,"slug":250,"title":251,"subtitle":38,"excerpt":252,"coverUrl":253,"locale":13,"readingMinutes":254,"publishedAt":255,"viewCount":256,"likeCount":19,"commentCount":19,"author":257,"vertical":258,"topic":259,"tags":262,"_count":269,"playground":270,"hasQuiz":17,"hasPlayground":17},"019fe660-cf2a-71df-b517-8d722f92cc37","weekly-cors-explained","CORS Explained: The Complete Guide (with Cheat Sheet)","A complete guide to CORS: the same-origin policy, preflight requests, and Access-Control-Allow-Origin headers — with worked examples and a cheat sheet.","\u002Fmedia\u002Fcovers\u002Fweekly-cors-explained.png",14,"2026-08-03T09:54:26.268Z",302,{"id":45,"name":46,"username":47,"avatarUrl":38,"headline":48},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":260,"name":261},"security","Security",[263,264,265,266],{"slug":57,"name":58,"color":38},{"slug":260,"name":261,"color":38},{"slug":51,"name":55,"color":38},{"slug":267,"name":268,"color":38},"tutorial","Tutorial",{"assessments":66},{"slug":250},{"id":272,"slug":273,"title":274,"subtitle":38,"excerpt":275,"coverUrl":276,"locale":13,"readingMinutes":41,"publishedAt":277,"viewCount":278,"likeCount":19,"commentCount":19,"author":279,"vertical":280,"topic":281,"tags":282,"_count":287,"playground":288,"hasQuiz":17,"hasPlayground":17},"019fe660-c754-703b-80fb-2254bb102ab7","scheduler-yield-main-thread","Your UI is freezing because you never gave the browser a break","Long synchronous tasks block the main thread and make your interface unresponsive. `scheduler.yield()` is the native way to hand control back to the browser mid-task so it can paint, handle input, and resume your work exactly where it left off.","\u002Fmedia\u002Fcovers\u002Fscheduler-yield-main-thread.png","2026-08-03T09:54:25.323Z",212,{"id":45,"name":46,"username":47,"avatarUrl":38,"headline":48},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":51,"name":52},[283,284,285,286],{"slug":51,"name":55,"color":38},{"slug":57,"name":58,"color":38},{"slug":84,"name":85,"color":38},{"slug":60,"name":61,"color":38},{"assessments":66},{"slug":273},{"page":66,"perPage":290,"total":291,"totalPages":113},12,50,[293,294,296,298,300,302,304,307,310,313,314],{"slug":57,"name":58,"color":38,"articles":291},{"slug":51,"name":55,"color":38,"articles":295},45,{"slug":60,"name":61,"color":38,"articles":297},44,{"slug":198,"name":202,"color":38,"articles":299},18,{"slug":184,"name":185,"color":38,"articles":301},9,{"slug":84,"name":85,"color":38,"articles":303},7,{"slug":305,"name":306,"color":38,"articles":113},"react","React",{"slug":308,"name":309,"color":38,"articles":41},"node","Node",{"slug":311,"name":312,"color":38,"articles":135},"ai","Ai",{"slug":267,"name":268,"color":38,"articles":135},{"slug":119,"name":123,"color":38,"articles":135}]