[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"verticals":3,"tag-javascript-1":32,"tags-all":291},[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":288},[34,68,89,109,129,151,170,190,209,229,252,270],{"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-f763-70e0-abdf-eded59c8e69a","overscroll-behavior-scroll-containment","You're blocking touchmove events to contain scroll. `overscroll-behavior` does it natively.",null,"When a scrollable container hits its edge, the page behind it starts scrolling too. Developers block this with JavaScript event handlers or body overflow tricks. overscroll-behavior is the CSS property that turns off scroll chaining in one line.","\u002Fmedia\u002Fcovers\u002Foverscroll-behavior-scroll-containment.png",4,"2026-08-12T07:38:53.786Z",75,{"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},"css","CSS",[54,56,59,62],{"slug":51,"name":55,"color":38},"Css",{"slug":57,"name":58,"color":38},"webdev","Webdev",{"slug":60,"name":61,"color":38},"frontend","Frontend",{"slug":63,"name":64,"color":38},"javascript","Javascript",{"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":80,"_count":87,"playground":88,"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.","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","2026-08-11T15:48:01.781Z",342,{"id":45,"name":46,"username":47,"avatarUrl":38,"headline":48},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":63,"name":79},"JavaScript",[81,82,83,84],{"slug":63,"name":64,"color":38},{"slug":57,"name":58,"color":38},{"slug":60,"name":61,"color":38},{"slug":85,"name":86,"color":38},"dom","Dom",{"assessments":66},{"slug":70},{"id":90,"slug":91,"title":92,"subtitle":38,"excerpt":93,"coverUrl":94,"locale":13,"readingMinutes":41,"publishedAt":95,"viewCount":96,"likeCount":19,"commentCount":19,"author":97,"vertical":98,"topic":99,"tags":100,"_count":107,"playground":108,"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",204,{"id":45,"name":46,"username":47,"avatarUrl":38,"headline":48},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":63,"name":79},[101,102,103,104],{"slug":63,"name":64,"color":38},{"slug":57,"name":58,"color":38},{"slug":60,"name":61,"color":38},{"slug":105,"name":106,"color":38},"performance","Performance",{"assessments":66},{"slug":91},{"id":110,"slug":111,"title":112,"subtitle":38,"excerpt":113,"coverUrl":114,"locale":13,"readingMinutes":41,"publishedAt":115,"viewCount":116,"likeCount":19,"commentCount":19,"author":117,"vertical":118,"topic":119,"tags":120,"_count":127,"playground":128,"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",212,{"id":45,"name":46,"username":47,"avatarUrl":38,"headline":48},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":63,"name":79},[121,122,123,124],{"slug":63,"name":64,"color":38},{"slug":57,"name":58,"color":38},{"slug":60,"name":61,"color":38},{"slug":125,"name":126,"color":38},"apis","Apis",{"assessments":66},{"slug":111},{"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":143,"_count":149,"playground":150,"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",184,{"id":45,"name":46,"username":47,"avatarUrl":38,"headline":48},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":141,"name":142},"html","HTML",[144,146,147,148],{"slug":141,"name":145,"color":38},"Html",{"slug":57,"name":58,"color":38},{"slug":60,"name":61,"color":38},{"slug":63,"name":64,"color":38},{"assessments":66},{"slug":131},{"id":152,"slug":153,"title":154,"subtitle":38,"excerpt":155,"coverUrl":156,"locale":13,"readingMinutes":157,"publishedAt":158,"viewCount":159,"likeCount":19,"commentCount":19,"author":160,"vertical":161,"topic":162,"tags":163,"_count":168,"playground":169,"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",164,{"id":45,"name":46,"username":47,"avatarUrl":38,"headline":48},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":63,"name":79},[164,165,166,167],{"slug":63,"name":64,"color":38},{"slug":57,"name":58,"color":38},{"slug":60,"name":61,"color":38},{"slug":105,"name":106,"color":38},{"assessments":66},{"slug":153},{"id":171,"slug":172,"title":173,"subtitle":38,"excerpt":174,"coverUrl":175,"locale":13,"readingMinutes":41,"publishedAt":176,"viewCount":177,"likeCount":19,"commentCount":19,"author":178,"vertical":179,"topic":180,"tags":181,"_count":188,"playground":189,"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",62,{"id":45,"name":46,"username":47,"avatarUrl":38,"headline":48},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":63,"name":79},[182,183,184,185],{"slug":63,"name":64,"color":38},{"slug":57,"name":58,"color":38},{"slug":60,"name":61,"color":38},{"slug":186,"name":187,"color":38},"intl","Intl",{"assessments":66},{"slug":172},{"id":191,"slug":192,"title":193,"subtitle":38,"excerpt":194,"coverUrl":195,"locale":13,"readingMinutes":41,"publishedAt":196,"viewCount":177,"likeCount":19,"commentCount":19,"author":197,"vertical":198,"topic":199,"tags":200,"_count":207,"playground":208,"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",{"id":45,"name":46,"username":47,"avatarUrl":38,"headline":48},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":63,"name":79},[201,202,203,204],{"slug":63,"name":64,"color":38},{"slug":57,"name":58,"color":38},{"slug":60,"name":61,"color":38},{"slug":205,"name":206,"color":38},"typescript","Typescript",{"assessments":66},{"slug":192},{"id":210,"slug":211,"title":212,"subtitle":38,"excerpt":213,"coverUrl":214,"locale":13,"readingMinutes":41,"publishedAt":215,"viewCount":216,"likeCount":19,"commentCount":19,"author":217,"vertical":218,"topic":219,"tags":220,"_count":227,"playground":228,"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",300,{"id":45,"name":46,"username":47,"avatarUrl":38,"headline":48},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":63,"name":79},[221,222,223,224],{"slug":63,"name":64,"color":38},{"slug":57,"name":58,"color":38},{"slug":60,"name":61,"color":38},{"slug":225,"name":226,"color":38},"async","Async",{"assessments":66},{"slug":211},{"id":230,"slug":231,"title":232,"subtitle":38,"excerpt":233,"coverUrl":234,"locale":13,"readingMinutes":235,"publishedAt":236,"viewCount":237,"likeCount":19,"commentCount":19,"author":238,"vertical":239,"topic":240,"tags":243,"_count":250,"playground":251,"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",323,{"id":45,"name":46,"username":47,"avatarUrl":38,"headline":48},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":241,"name":242},"security","Security",[244,245,246,247],{"slug":57,"name":58,"color":38},{"slug":241,"name":242,"color":38},{"slug":63,"name":64,"color":38},{"slug":248,"name":249,"color":38},"tutorial","Tutorial",{"assessments":66},{"slug":231},{"id":253,"slug":254,"title":255,"subtitle":38,"excerpt":256,"coverUrl":257,"locale":13,"readingMinutes":41,"publishedAt":258,"viewCount":259,"likeCount":19,"commentCount":19,"author":260,"vertical":261,"topic":262,"tags":263,"_count":268,"playground":269,"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",221,{"id":45,"name":46,"username":47,"avatarUrl":38,"headline":48},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":63,"name":79},[264,265,266,267],{"slug":63,"name":64,"color":38},{"slug":57,"name":58,"color":38},{"slug":105,"name":106,"color":38},{"slug":60,"name":61,"color":38},{"assessments":66},{"slug":254},{"id":271,"slug":272,"title":273,"subtitle":38,"excerpt":274,"coverUrl":275,"locale":13,"readingMinutes":135,"publishedAt":276,"viewCount":277,"likeCount":19,"commentCount":19,"author":278,"vertical":279,"topic":280,"tags":281,"_count":286,"playground":287,"hasQuiz":17,"hasPlayground":17},"019fe660-c020-760c-b4c7-46c1465e25bd","css-light-dark-function","You're writing dark-mode colors twice. `light-dark()` fixes that.","Every `@media (prefers-color-scheme: dark)` block duplicates your color definitions. `light-dark()` lets you write both values on the same line, in the same rule, with no separate block and no build step. Baseline 2024.","\u002Fmedia\u002Fcovers\u002Fcss-light-dark-function.png","2026-08-02T08:29:56.698Z",230,{"id":45,"name":46,"username":47,"avatarUrl":38,"headline":48},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":51,"name":52},[282,283,284,285],{"slug":51,"name":55,"color":38},{"slug":57,"name":58,"color":38},{"slug":60,"name":61,"color":38},{"slug":63,"name":64,"color":38},{"assessments":66},{"slug":272},{"page":66,"perPage":289,"total":290,"totalPages":41},12,46,[292,294,295,297,299,301,303,306,309,312,315,316,317,320,323],{"slug":57,"name":58,"color":38,"articles":293},51,{"slug":63,"name":64,"color":38,"articles":290},{"slug":60,"name":61,"color":38,"articles":296},45,{"slug":51,"name":55,"color":38,"articles":298},19,{"slug":205,"name":206,"color":38,"articles":300},9,{"slug":105,"name":106,"color":38,"articles":302},7,{"slug":304,"name":305,"color":38,"articles":135},"react","React",{"slug":307,"name":308,"color":38,"articles":41},"node","Node",{"slug":310,"name":311,"color":38,"articles":41},"grammar","Grammar",{"slug":313,"name":314,"color":38,"articles":157},"ai","Ai",{"slug":248,"name":249,"color":38,"articles":157},{"slug":141,"name":145,"color":38,"articles":157},{"slug":318,"name":319,"color":38,"articles":31},"verbs","Verbs",{"slug":321,"name":322,"color":38,"articles":31},"a1","A1",{"slug":324,"name":325,"color":38,"articles":31},"turkish","Turkish"]