[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"verticals":3,"search-suggestions":44,"tag-javascript-5":92,"tags-all":333},[4,20,32],{"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","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.","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.","Grammar explained the way good documentation explains an API — one idea at a time, each with a quiz.","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,{"id":33,"slug":34,"name":35,"tagline":36,"description":37,"accentFrom":38,"accentTo":39,"icon":40,"defaultLocale":13,"locales":41,"features":42,"position":43},"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","◉",[13],{"courses":18,"paths":18,"articles":17,"exams":18,"flashcards":18,"packages":18,"community":17,"certificates":18,"teams":18,"commerce":18},3,[45,49,53,57,61,65,69,73,77,81,84,88],{"slug":46,"name":47,"articles":48},"webdev","Webdev",111,{"slug":50,"name":51,"articles":52},"javascript","Javascript",93,{"slug":54,"name":55,"articles":56},"frontend","Frontend",73,{"slug":58,"name":59,"articles":60},"tutorial","Tutorial",39,{"slug":62,"name":63,"articles":64},"css","Css",36,{"slug":66,"name":67,"articles":68},"typescript","Typescript",16,{"slug":70,"name":71,"articles":72},"performance","Performance",14,{"slug":74,"name":75,"articles":76},"react","React",13,{"slug":78,"name":79,"articles":80},"browser","Browser",10,{"slug":82,"name":83,"articles":80},"node","Node",{"slug":85,"name":86,"articles":87},"html","Html",8,{"slug":89,"name":90,"articles":91},"accessibility","Accessibility",7,{"items":93,"meta":331},[94,122,140,160,180,198,218,236,256,276,294,313],{"id":95,"slug":96,"title":97,"subtitle":98,"excerpt":99,"coverUrl":100,"locale":13,"readingMinutes":101,"publishedAt":102,"viewCount":103,"likeCount":19,"commentCount":19,"author":104,"vertical":109,"topic":110,"tags":112,"_count":119,"playground":121,"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",741,{"id":105,"name":106,"username":107,"avatarUrl":98,"headline":108},"019fe637-3c25-7088-9034-39c9f15dc3c8","Parsa Jiravand","parsa","Frontend engineer · building bestpractic",{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":50,"name":111},"JavaScript",[113,114,115,116],{"slug":50,"name":51,"color":98},{"slug":46,"name":47,"color":98},{"slug":54,"name":55,"color":98},{"slug":117,"name":118,"color":98},"dom","Dom",{"assessments":120},1,{"slug":96},{"id":123,"slug":124,"title":125,"subtitle":98,"excerpt":126,"coverUrl":127,"locale":13,"readingMinutes":101,"publishedAt":128,"viewCount":129,"likeCount":19,"commentCount":19,"author":130,"vertical":131,"topic":132,"tags":133,"_count":138,"playground":139,"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",594,{"id":105,"name":106,"username":107,"avatarUrl":98,"headline":108},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":50,"name":111},[134,135,136,137],{"slug":50,"name":51,"color":98},{"slug":46,"name":47,"color":98},{"slug":54,"name":55,"color":98},{"slug":70,"name":71,"color":98},{"assessments":120},{"slug":124},{"id":141,"slug":142,"title":143,"subtitle":98,"excerpt":144,"coverUrl":145,"locale":13,"readingMinutes":101,"publishedAt":146,"viewCount":147,"likeCount":19,"commentCount":19,"author":148,"vertical":149,"topic":150,"tags":151,"_count":158,"playground":159,"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",1454,{"id":105,"name":106,"username":107,"avatarUrl":98,"headline":108},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":50,"name":111},[152,153,154,155],{"slug":50,"name":51,"color":98},{"slug":46,"name":47,"color":98},{"slug":54,"name":55,"color":98},{"slug":156,"name":157,"color":98},"apis","Apis",{"assessments":120},{"slug":142},{"id":161,"slug":162,"title":163,"subtitle":98,"excerpt":164,"coverUrl":165,"locale":13,"readingMinutes":166,"publishedAt":167,"viewCount":168,"likeCount":19,"commentCount":19,"author":169,"vertical":170,"topic":171,"tags":173,"_count":178,"playground":179,"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",466,{"id":105,"name":106,"username":107,"avatarUrl":98,"headline":108},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":85,"name":172},"HTML",[174,175,176,177],{"slug":85,"name":86,"color":98},{"slug":46,"name":47,"color":98},{"slug":54,"name":55,"color":98},{"slug":50,"name":51,"color":98},{"assessments":120},{"slug":162},{"id":181,"slug":182,"title":183,"subtitle":98,"excerpt":184,"coverUrl":185,"locale":13,"readingMinutes":43,"publishedAt":186,"viewCount":187,"likeCount":19,"commentCount":19,"author":188,"vertical":189,"topic":190,"tags":191,"_count":196,"playground":197,"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","2026-08-08T07:00:09.988Z",525,{"id":105,"name":106,"username":107,"avatarUrl":98,"headline":108},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":50,"name":111},[192,193,194,195],{"slug":50,"name":51,"color":98},{"slug":46,"name":47,"color":98},{"slug":54,"name":55,"color":98},{"slug":70,"name":71,"color":98},{"assessments":120},{"slug":182},{"id":199,"slug":200,"title":201,"subtitle":98,"excerpt":202,"coverUrl":203,"locale":13,"readingMinutes":101,"publishedAt":204,"viewCount":205,"likeCount":19,"commentCount":19,"author":206,"vertical":207,"topic":208,"tags":209,"_count":216,"playground":217,"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",354,{"id":105,"name":106,"username":107,"avatarUrl":98,"headline":108},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":50,"name":111},[210,211,212,213],{"slug":50,"name":51,"color":98},{"slug":46,"name":47,"color":98},{"slug":54,"name":55,"color":98},{"slug":214,"name":215,"color":98},"intl","Intl",{"assessments":120},{"slug":200},{"id":219,"slug":220,"title":221,"subtitle":98,"excerpt":222,"coverUrl":223,"locale":13,"readingMinutes":101,"publishedAt":224,"viewCount":225,"likeCount":19,"commentCount":19,"author":226,"vertical":227,"topic":228,"tags":229,"_count":234,"playground":235,"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",329,{"id":105,"name":106,"username":107,"avatarUrl":98,"headline":108},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":50,"name":111},[230,231,232,233],{"slug":50,"name":51,"color":98},{"slug":46,"name":47,"color":98},{"slug":54,"name":55,"color":98},{"slug":66,"name":67,"color":98},{"assessments":120},{"slug":220},{"id":237,"slug":238,"title":239,"subtitle":98,"excerpt":240,"coverUrl":241,"locale":13,"readingMinutes":101,"publishedAt":242,"viewCount":243,"likeCount":19,"commentCount":19,"author":244,"vertical":245,"topic":246,"tags":247,"_count":254,"playground":255,"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",567,{"id":105,"name":106,"username":107,"avatarUrl":98,"headline":108},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":50,"name":111},[248,249,250,251],{"slug":50,"name":51,"color":98},{"slug":46,"name":47,"color":98},{"slug":54,"name":55,"color":98},{"slug":252,"name":253,"color":98},"async","Async",{"assessments":120},{"slug":238},{"id":257,"slug":258,"title":259,"subtitle":98,"excerpt":260,"coverUrl":261,"locale":13,"readingMinutes":72,"publishedAt":262,"viewCount":263,"likeCount":19,"commentCount":19,"author":264,"vertical":265,"topic":266,"tags":269,"_count":274,"playground":275,"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","2026-08-03T09:54:26.268Z",711,{"id":105,"name":106,"username":107,"avatarUrl":98,"headline":108},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":267,"name":268},"security","Security",[270,271,272,273],{"slug":46,"name":47,"color":98},{"slug":267,"name":268,"color":98},{"slug":50,"name":51,"color":98},{"slug":58,"name":59,"color":98},{"assessments":120},{"slug":258},{"id":277,"slug":278,"title":279,"subtitle":98,"excerpt":280,"coverUrl":281,"locale":13,"readingMinutes":166,"publishedAt":282,"viewCount":283,"likeCount":19,"commentCount":19,"author":284,"vertical":285,"topic":286,"tags":287,"_count":292,"playground":293,"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",506,{"id":105,"name":106,"username":107,"avatarUrl":98,"headline":108},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":50,"name":111},[288,289,290,291],{"slug":50,"name":51,"color":98},{"slug":46,"name":47,"color":98},{"slug":70,"name":71,"color":98},{"slug":54,"name":55,"color":98},{"assessments":120},{"slug":278},{"id":295,"slug":296,"title":297,"subtitle":98,"excerpt":298,"coverUrl":299,"locale":13,"readingMinutes":166,"publishedAt":300,"viewCount":301,"likeCount":19,"commentCount":19,"author":302,"vertical":303,"topic":304,"tags":306,"_count":311,"playground":312,"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",483,{"id":105,"name":106,"username":107,"avatarUrl":98,"headline":108},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":62,"name":305},"CSS",[307,308,309,310],{"slug":62,"name":63,"color":98},{"slug":46,"name":47,"color":98},{"slug":54,"name":55,"color":98},{"slug":50,"name":51,"color":98},{"assessments":120},{"slug":296},{"id":314,"slug":315,"title":316,"subtitle":98,"excerpt":317,"coverUrl":318,"locale":13,"readingMinutes":166,"publishedAt":319,"viewCount":320,"likeCount":19,"commentCount":19,"author":321,"vertical":322,"topic":323,"tags":324,"_count":329,"playground":330,"hasQuiz":17,"hasPlayground":17},"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",436,{"id":105,"name":106,"username":107,"avatarUrl":98,"headline":108},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":50,"name":111},[325,326,327,328],{"slug":50,"name":51,"color":98},{"slug":46,"name":47,"color":98},{"slug":54,"name":55,"color":98},{"slug":66,"name":67,"color":98},{"assessments":120},{"slug":315},{"page":166,"perPage":332,"total":52,"totalPages":87},12,[334,335,336,337,338,339,340,341,342,343,344,345,346,350,353,356,359,360,363,366,369,372,373,374,377,380,383,386,389,392,395,398,401,404,407,410],{"slug":46,"name":47,"color":98,"articles":48},{"slug":50,"name":51,"color":98,"articles":52},{"slug":54,"name":55,"color":98,"articles":56},{"slug":58,"name":59,"color":98,"articles":60},{"slug":62,"name":63,"color":98,"articles":64},{"slug":66,"name":67,"color":98,"articles":68},{"slug":70,"name":71,"color":98,"articles":72},{"slug":74,"name":75,"color":98,"articles":76},{"slug":82,"name":83,"color":98,"articles":80},{"slug":78,"name":79,"color":98,"articles":80},{"slug":85,"name":86,"color":98,"articles":87},{"slug":89,"name":90,"color":98,"articles":91},{"slug":347,"name":348,"color":98,"articles":349},"programming","Programming",6,{"slug":351,"name":352,"color":98,"articles":349},"grammar","Grammar",{"slug":354,"name":355,"color":98,"articles":166},"nestjs","Nestjs",{"slug":357,"name":358,"color":98,"articles":101},"nextjs","Nextjs",{"slug":156,"name":157,"color":98,"articles":101},{"slug":361,"name":362,"color":98,"articles":43},"nuxt","Nuxt",{"slug":364,"name":365,"color":98,"articles":43},"ssr","SSR",{"slug":367,"name":368,"color":98,"articles":43},"ai","Ai",{"slug":370,"name":371,"color":98,"articles":43},"vue","Vue",{"slug":267,"name":268,"color":98,"articles":31},{"slug":252,"name":253,"color":98,"articles":31},{"slug":375,"name":376,"color":98,"articles":31},"forms","Forms",{"slug":378,"name":379,"color":98,"articles":31},"api","API",{"slug":381,"name":382,"color":98,"articles":31},"english","English",{"slug":384,"name":385,"color":98,"articles":31},"verbs","Verbs",{"slug":387,"name":388,"color":98,"articles":31},"spanish","Spanish",{"slug":390,"name":391,"color":98,"articles":31},"a1","A1",{"slug":393,"name":394,"color":98,"articles":31},"a2","A2",{"slug":396,"name":397,"color":98,"articles":31},"tenses","Tenses",{"slug":399,"name":400,"color":98,"articles":31},"turkish","Turkish",{"slug":402,"name":403,"color":98,"articles":31},"career","Career",{"slug":405,"name":406,"color":98,"articles":31},"beginners","Beginners",{"slug":408,"name":409,"color":98,"articles":31},"productivity","Productivity",{"slug":411,"name":412,"color":98,"articles":31},"discuss","Discuss"]