[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"tag-javascript-9":3,"verticals":270,"search-suggestions":304,"tags-all":335},{"items":4,"meta":266},[5,46,66,86,108,126,146,166,186,209,227,248],{"id":6,"slug":7,"title":8,"subtitle":9,"excerpt":10,"coverUrl":11,"locale":12,"readingMinutes":13,"publishedAt":14,"viewCount":15,"likeCount":16,"commentCount":16,"author":17,"vertical":22,"topic":27,"tags":30,"_count":42,"playground":44,"hasQuiz":45,"hasPlayground":45},"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","en",4,"2026-08-11T15:48:01.781Z",1026,0,{"id":18,"name":19,"username":20,"avatarUrl":9,"headline":21},"019fe637-3c25-7088-9034-39c9f15dc3c8","Parsa Jiravand","parsa","Frontend engineer · building bestpractic",{"slug":23,"name":24,"accentFrom":25,"accentTo":26},"dev","Web Development","violet-500","cyan-400",{"slug":28,"name":29},"javascript","JavaScript",[31,33,36,39],{"slug":28,"name":32,"color":9},"Javascript",{"slug":34,"name":35,"color":9},"webdev","Webdev",{"slug":37,"name":38,"color":9},"frontend","Frontend",{"slug":40,"name":41,"color":9},"dom","Dom",{"assessments":43},1,{"slug":7},true,{"id":47,"slug":48,"title":49,"subtitle":9,"excerpt":50,"coverUrl":51,"locale":12,"readingMinutes":13,"publishedAt":52,"viewCount":53,"likeCount":16,"commentCount":16,"author":54,"vertical":55,"topic":56,"tags":57,"_count":64,"playground":65,"hasQuiz":45,"hasPlayground":45},"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",895,{"id":18,"name":19,"username":20,"avatarUrl":9,"headline":21},{"slug":23,"name":24,"accentFrom":25,"accentTo":26},{"slug":28,"name":29},[58,59,60,61],{"slug":28,"name":32,"color":9},{"slug":34,"name":35,"color":9},{"slug":37,"name":38,"color":9},{"slug":62,"name":63,"color":9},"performance","Performance",{"assessments":43},{"slug":48},{"id":67,"slug":68,"title":69,"subtitle":9,"excerpt":70,"coverUrl":71,"locale":12,"readingMinutes":13,"publishedAt":72,"viewCount":73,"likeCount":16,"commentCount":16,"author":74,"vertical":75,"topic":76,"tags":77,"_count":84,"playground":85,"hasQuiz":45,"hasPlayground":45},"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",1971,{"id":18,"name":19,"username":20,"avatarUrl":9,"headline":21},{"slug":23,"name":24,"accentFrom":25,"accentTo":26},{"slug":28,"name":29},[78,79,80,81],{"slug":28,"name":32,"color":9},{"slug":34,"name":35,"color":9},{"slug":37,"name":38,"color":9},{"slug":82,"name":83,"color":9},"apis","Apis",{"assessments":43},{"slug":68},{"id":87,"slug":88,"title":89,"subtitle":9,"excerpt":90,"coverUrl":91,"locale":12,"readingMinutes":92,"publishedAt":93,"viewCount":94,"likeCount":16,"commentCount":16,"author":95,"vertical":96,"topic":97,"tags":100,"_count":106,"playground":107,"hasQuiz":45,"hasPlayground":45},"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",996,{"id":18,"name":19,"username":20,"avatarUrl":9,"headline":21},{"slug":23,"name":24,"accentFrom":25,"accentTo":26},{"slug":98,"name":99},"html","HTML",[101,103,104,105],{"slug":98,"name":102,"color":9},"Html",{"slug":34,"name":35,"color":9},{"slug":37,"name":38,"color":9},{"slug":28,"name":32,"color":9},{"assessments":43},{"slug":88},{"id":109,"slug":110,"title":111,"subtitle":9,"excerpt":112,"coverUrl":113,"locale":12,"readingMinutes":13,"publishedAt":114,"viewCount":115,"likeCount":16,"commentCount":16,"author":116,"vertical":117,"topic":118,"tags":119,"_count":124,"playground":125,"hasQuiz":45,"hasPlayground":45},"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","2026-08-08T07:00:09.988Z",1024,{"id":18,"name":19,"username":20,"avatarUrl":9,"headline":21},{"slug":23,"name":24,"accentFrom":25,"accentTo":26},{"slug":28,"name":29},[120,121,122,123],{"slug":28,"name":32,"color":9},{"slug":34,"name":35,"color":9},{"slug":37,"name":38,"color":9},{"slug":62,"name":63,"color":9},{"assessments":43},{"slug":110},{"id":127,"slug":128,"title":129,"subtitle":9,"excerpt":130,"coverUrl":131,"locale":12,"readingMinutes":13,"publishedAt":132,"viewCount":133,"likeCount":16,"commentCount":16,"author":134,"vertical":135,"topic":136,"tags":137,"_count":144,"playground":145,"hasQuiz":45,"hasPlayground":45},"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",639,{"id":18,"name":19,"username":20,"avatarUrl":9,"headline":21},{"slug":23,"name":24,"accentFrom":25,"accentTo":26},{"slug":28,"name":29},[138,139,140,141],{"slug":28,"name":32,"color":9},{"slug":34,"name":35,"color":9},{"slug":37,"name":38,"color":9},{"slug":142,"name":143,"color":9},"intl","Intl",{"assessments":43},{"slug":128},{"id":147,"slug":148,"title":149,"subtitle":9,"excerpt":150,"coverUrl":151,"locale":12,"readingMinutes":13,"publishedAt":152,"viewCount":153,"likeCount":16,"commentCount":16,"author":154,"vertical":155,"topic":156,"tags":157,"_count":164,"playground":165,"hasQuiz":45,"hasPlayground":45},"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",537,{"id":18,"name":19,"username":20,"avatarUrl":9,"headline":21},{"slug":23,"name":24,"accentFrom":25,"accentTo":26},{"slug":28,"name":29},[158,159,160,161],{"slug":28,"name":32,"color":9},{"slug":34,"name":35,"color":9},{"slug":37,"name":38,"color":9},{"slug":162,"name":163,"color":9},"typescript","Typescript",{"assessments":43},{"slug":148},{"id":167,"slug":168,"title":169,"subtitle":9,"excerpt":170,"coverUrl":171,"locale":12,"readingMinutes":13,"publishedAt":172,"viewCount":173,"likeCount":16,"commentCount":16,"author":174,"vertical":175,"topic":176,"tags":177,"_count":184,"playground":185,"hasQuiz":45,"hasPlayground":45},"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",748,{"id":18,"name":19,"username":20,"avatarUrl":9,"headline":21},{"slug":23,"name":24,"accentFrom":25,"accentTo":26},{"slug":28,"name":29},[178,179,180,181],{"slug":28,"name":32,"color":9},{"slug":34,"name":35,"color":9},{"slug":37,"name":38,"color":9},{"slug":182,"name":183,"color":9},"async","Async",{"assessments":43},{"slug":168},{"id":187,"slug":188,"title":189,"subtitle":9,"excerpt":190,"coverUrl":191,"locale":12,"readingMinutes":192,"publishedAt":193,"viewCount":194,"likeCount":16,"commentCount":16,"author":195,"vertical":196,"topic":197,"tags":200,"_count":207,"playground":208,"hasQuiz":45,"hasPlayground":45},"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",15,"2026-08-03T09:54:26.268Z",1069,{"id":18,"name":19,"username":20,"avatarUrl":9,"headline":21},{"slug":23,"name":24,"accentFrom":25,"accentTo":26},{"slug":198,"name":199},"security","Security",[201,202,203,204],{"slug":34,"name":35,"color":9},{"slug":198,"name":199,"color":9},{"slug":28,"name":32,"color":9},{"slug":205,"name":206,"color":9},"tutorial","Tutorial",{"assessments":43},{"slug":188},{"id":210,"slug":211,"title":212,"subtitle":9,"excerpt":213,"coverUrl":214,"locale":12,"readingMinutes":92,"publishedAt":215,"viewCount":216,"likeCount":16,"commentCount":16,"author":217,"vertical":218,"topic":219,"tags":220,"_count":225,"playground":226,"hasQuiz":45,"hasPlayground":45},"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",767,{"id":18,"name":19,"username":20,"avatarUrl":9,"headline":21},{"slug":23,"name":24,"accentFrom":25,"accentTo":26},{"slug":28,"name":29},[221,222,223,224],{"slug":28,"name":32,"color":9},{"slug":34,"name":35,"color":9},{"slug":62,"name":63,"color":9},{"slug":37,"name":38,"color":9},{"assessments":43},{"slug":211},{"id":228,"slug":229,"title":230,"subtitle":9,"excerpt":231,"coverUrl":232,"locale":12,"readingMinutes":92,"publishedAt":233,"viewCount":234,"likeCount":16,"commentCount":16,"author":235,"vertical":236,"topic":237,"tags":240,"_count":246,"playground":247,"hasQuiz":45,"hasPlayground":45},"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",695,{"id":18,"name":19,"username":20,"avatarUrl":9,"headline":21},{"slug":23,"name":24,"accentFrom":25,"accentTo":26},{"slug":238,"name":239},"css","CSS",[241,243,244,245],{"slug":238,"name":242,"color":9},"Css",{"slug":34,"name":35,"color":9},{"slug":37,"name":38,"color":9},{"slug":28,"name":32,"color":9},{"assessments":43},{"slug":229},{"id":249,"slug":250,"title":251,"subtitle":9,"excerpt":252,"coverUrl":253,"locale":12,"readingMinutes":92,"publishedAt":254,"viewCount":255,"likeCount":16,"commentCount":16,"author":256,"vertical":257,"topic":258,"tags":259,"_count":264,"playground":265,"hasQuiz":45,"hasPlayground":45},"019fe660-b8d7-7515-892c-bd576110158c","url-parse-safe-parsing","You've been wrapping `new URL()` in try\u002Fcatch. `URL.parse()` does it natively.","Validating an untrusted URL before parsing it used to mean a try\u002Fcatch wrapper or a regex. `URL.canParse()` checks validity without constructing. `URL.parse()` parses and returns null on failure. Both are Baseline 2024 — no wrapper needed.","\u002Fmedia\u002Fcovers\u002Furl-parse-safe-parsing.png","2026-08-01T08:27:13.710Z",721,{"id":18,"name":19,"username":20,"avatarUrl":9,"headline":21},{"slug":23,"name":24,"accentFrom":25,"accentTo":26},{"slug":28,"name":29},[260,261,262,263],{"slug":28,"name":32,"color":9},{"slug":34,"name":35,"color":9},{"slug":37,"name":38,"color":9},{"slug":162,"name":163,"color":9},{"assessments":43},{"slug":250},{"page":267,"perPage":268,"total":269,"totalPages":268},9,12,141,[271,280,292],{"id":272,"slug":23,"name":24,"tagline":273,"description":274,"accentFrom":25,"accentTo":26,"icon":275,"defaultLocale":12,"locales":276,"features":278,"position":16},"019fe637-3d33-714b-b57f-23e163ffca0c","Read it. Run it. Prove it.","A post a day on modern web development — most with an editable playground and a quiz that explains every answer. Free, no account needed.","◇",[12,277],"fa",{"courses":45,"paths":45,"articles":45,"exams":279,"flashcards":279,"packages":45,"community":45,"certificates":45,"teams":45,"commerce":45},false,{"id":281,"slug":282,"name":283,"tagline":284,"description":285,"accentFrom":286,"accentTo":25,"icon":287,"defaultLocale":12,"locales":288,"features":290,"position":291},"019fe637-3dc2-754c-8657-0f175bfee7c6","lang","Languages","Learn a language the way you learn a codebase.","Grammar explained the way good documentation explains an API — one idea at a time, each with a quiz.","amber-400","⌘",[12,277,289],"es",{"courses":279,"paths":279,"articles":45,"exams":279,"flashcards":45,"packages":279,"community":45,"certificates":45,"teams":279,"commerce":279},2,{"id":293,"slug":294,"name":295,"tagline":296,"description":297,"accentFrom":298,"accentTo":299,"icon":300,"defaultLocale":12,"locales":301,"features":302,"position":303},"7b3c16f2-931d-410e-802e-e1fa4edab7de","soft","Soft Skills","The half of the job nobody wrote documentation for.","Weekly, on the parts of working life that decide more than your code does — first weeks, meetings, interviews, promotions, and the people around you. Written from what actually happens, and recorded as a podcast you can listen to on the walk.","emerald-400","teal-300","◉",[12],{"courses":279,"paths":279,"articles":45,"exams":279,"flashcards":279,"packages":279,"community":45,"certificates":279,"teams":279,"commerce":279},3,[305,307,308,310,312,314,316,318,322,326,330,334],{"slug":34,"name":35,"articles":306},174,{"slug":28,"name":32,"articles":269},{"slug":37,"name":38,"articles":309},96,{"slug":205,"name":206,"articles":311},71,{"slug":238,"name":242,"articles":313},51,{"slug":62,"name":63,"articles":315},30,{"slug":162,"name":163,"articles":317},25,{"slug":319,"name":320,"articles":321},"react","React",20,{"slug":323,"name":324,"articles":325},"programming","Programming",19,{"slug":327,"name":328,"articles":329},"browser","Browser",18,{"slug":331,"name":332,"articles":333},"node","Node",16,{"slug":98,"name":102,"articles":268},[336,337,338,339,340,341,342,343,344,345,346,347,348,352,356,359,362,366,369,372,376,379,383,384,387,388,391,394,397,398,401,402,405,408,411,414,417,420,423,426],{"slug":34,"name":35,"color":9,"articles":306},{"slug":28,"name":32,"color":9,"articles":269},{"slug":37,"name":38,"color":9,"articles":309},{"slug":205,"name":206,"color":9,"articles":311},{"slug":238,"name":242,"color":9,"articles":313},{"slug":62,"name":63,"color":9,"articles":315},{"slug":162,"name":163,"color":9,"articles":317},{"slug":319,"name":320,"color":9,"articles":321},{"slug":323,"name":324,"color":9,"articles":325},{"slug":327,"name":328,"color":9,"articles":329},{"slug":331,"name":332,"color":9,"articles":333},{"slug":98,"name":102,"color":9,"articles":268},{"slug":349,"name":350,"color":9,"articles":351},"nextjs","Nextjs",11,{"slug":353,"name":354,"color":9,"articles":355},"vue","Vue",10,{"slug":357,"name":358,"color":9,"articles":355},"accessibility","Accessibility",{"slug":360,"name":361,"color":9,"articles":267},"nestjs","Nestjs",{"slug":363,"name":364,"color":9,"articles":365},"nuxt","Nuxt",8,{"slug":367,"name":368,"color":9,"articles":365},"career","Career",{"slug":370,"name":371,"color":9,"articles":365},"discuss","Discuss",{"slug":373,"name":374,"color":9,"articles":375},"beginners","Beginners",7,{"slug":377,"name":378,"color":9,"articles":375},"productivity","Productivity",{"slug":380,"name":381,"color":9,"articles":382},"grammar","Grammar",6,{"slug":198,"name":199,"color":9,"articles":92},{"slug":385,"name":386,"color":9,"articles":13},"ssr","SSR",{"slug":82,"name":83,"color":9,"articles":13},{"slug":389,"name":390,"color":9,"articles":303},"ai","Ai",{"slug":392,"name":393,"color":9,"articles":303},"api","API",{"slug":395,"name":396,"color":9,"articles":303},"caching","Caching",{"slug":182,"name":183,"color":9,"articles":291},{"slug":399,"name":400,"color":9,"articles":291},"forms","Forms",{"slug":40,"name":41,"color":9,"articles":291},{"slug":403,"name":404,"color":9,"articles":291},"backend","Backend",{"slug":406,"name":407,"color":9,"articles":291},"english","English",{"slug":409,"name":410,"color":9,"articles":291},"verbs","Verbs",{"slug":412,"name":413,"color":9,"articles":291},"spanish","Spanish",{"slug":415,"name":416,"color":9,"articles":291},"a1","A1",{"slug":418,"name":419,"color":9,"articles":291},"a2","A2",{"slug":421,"name":422,"color":9,"articles":291},"tenses","Tenses",{"slug":424,"name":425,"color":9,"articles":291},"turkish","Turkish",{"slug":427,"name":428,"color":9,"articles":291},"animation","Animation"]