[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"verticals":3,"tag-webdev-14":44,"tags-all":288,"search-suggestions":410},[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,{"items":45,"meta":283},[46,80,101,122,140,159,177,196,215,232,249,266],{"id":47,"slug":48,"title":49,"subtitle":50,"excerpt":51,"coverUrl":52,"locale":13,"readingMinutes":53,"publishedAt":54,"viewCount":55,"likeCount":19,"commentCount":19,"author":56,"vertical":61,"topic":62,"tags":65,"_count":77,"playground":79,"hasQuiz":17,"hasPlayground":17},"019fe660-1be2-74dd-aa56-0c8fd84204fd","promise-concurrency-all-settled-any-race","You reach for `Promise.all` for every concurrent request. Here's when to use the other three.",null,"`Promise.all` fails the moment any one request fails. `allSettled`, `any`, and `race` each solve a different concurrency problem — dashboard partial results, CDN failover, and timeouts. Here's the taxonomy.","\u002Fmedia\u002Fcovers\u002Fpromise-concurrency-all-settled-any-race.png",5,"2026-07-13T09:36:32.501Z",516,{"id":57,"name":58,"username":59,"avatarUrl":50,"headline":60},"019fe637-3c25-7088-9034-39c9f15dc3c8","Parsa Jiravand","parsa","Frontend engineer · building bestpractic",{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":63,"name":64},"javascript","JavaScript",[66,68,71,74],{"slug":63,"name":67,"color":50},"Javascript",{"slug":69,"name":70,"color":50},"webdev","Webdev",{"slug":72,"name":73,"color":50},"frontend","Frontend",{"slug":75,"name":76,"color":50},"node","Node",{"assessments":78},1,{"slug":48},{"id":81,"slug":82,"title":83,"subtitle":50,"excerpt":84,"coverUrl":85,"locale":13,"readingMinutes":86,"publishedAt":87,"viewCount":88,"likeCount":19,"commentCount":19,"author":89,"vertical":90,"topic":91,"tags":92,"_count":99,"playground":100,"hasQuiz":17,"hasPlayground":17},"019fe660-1462-723e-9605-66ffa7e98f42","popover-api-native-popovers","Your dropdown is a div. The browser has a native popover now.","Custom dropdowns, tooltips, and menus built with stacked divs and click-outside listeners — the Popover API landed in every browser in 2024, and the baseline version is two HTML attributes.","\u002Fmedia\u002Fcovers\u002Fpopover-api-native-popovers.png",4,"2026-07-12T08:24:42.323Z",485,{"id":57,"name":58,"username":59,"avatarUrl":50,"headline":60},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":63,"name":64},[93,94,95,96],{"slug":69,"name":70,"color":50},{"slug":72,"name":73,"color":50},{"slug":63,"name":67,"color":50},{"slug":97,"name":98,"color":50},"css","Css",{"assessments":78},{"slug":82},{"id":102,"slug":103,"title":104,"subtitle":50,"excerpt":105,"coverUrl":106,"locale":13,"readingMinutes":53,"publishedAt":107,"viewCount":108,"likeCount":19,"commentCount":19,"author":109,"vertical":110,"topic":111,"tags":114,"_count":120,"playground":121,"hasQuiz":17,"hasPlayground":17},"019fe660-0d25-72d6-8fd8-3cf3c3592e54","typescript-satisfies-operator","Your TypeScript config objects are losing type information. `satisfies` fixes it.","Type annotations widen your object types and erase the precise values TypeScript inferred. The `satisfies` operator validates against a type without changing what TypeScript keeps — you get the check without the widening.","\u002Fmedia\u002Fcovers\u002Ftypescript-satisfies-operator.png","2026-07-11T08:03:26.200Z",535,{"id":57,"name":58,"username":59,"avatarUrl":50,"headline":60},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":112,"name":113},"typescript","TypeScript",[115,117,118,119],{"slug":112,"name":116,"color":50},"Typescript",{"slug":69,"name":70,"color":50},{"slug":63,"name":67,"color":50},{"slug":72,"name":73,"color":50},{"assessments":78},{"slug":103},{"id":123,"slug":124,"title":125,"subtitle":50,"excerpt":126,"coverUrl":127,"locale":13,"readingMinutes":86,"publishedAt":128,"viewCount":129,"likeCount":19,"commentCount":19,"author":130,"vertical":131,"topic":132,"tags":133,"_count":138,"playground":139,"hasQuiz":17,"hasPlayground":17},"019fe660-0596-7433-9dc2-0fc620be2d0f","structuredclone-deep-clone","You've been deep-cloning objects with a JSON hack. `structuredClone` does it right.","JSON.parse(JSON.stringify(obj)) silently corrupts Dates, Maps, Sets, and undefined values. structuredClone is the native replacement — no library, no import, no surprises.","\u002Fmedia\u002Fcovers\u002Fstructuredclone-deep-clone.png","2026-07-10T09:43:33.966Z",501,{"id":57,"name":58,"username":59,"avatarUrl":50,"headline":60},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":63,"name":64},[134,135,136,137],{"slug":63,"name":67,"color":50},{"slug":69,"name":70,"color":50},{"slug":72,"name":73,"color":50},{"slug":75,"name":76,"color":50},{"assessments":78},{"slug":124},{"id":141,"slug":142,"title":143,"subtitle":50,"excerpt":144,"coverUrl":145,"locale":13,"readingMinutes":53,"publishedAt":146,"viewCount":147,"likeCount":19,"commentCount":19,"author":148,"vertical":149,"topic":150,"tags":152,"_count":157,"playground":158,"hasQuiz":17,"hasPlayground":17},"019fe65f-fe39-767c-9ce8-da4db5144b1d","css-nesting-sass-replaced","You kept Sass for one reason. Native CSS nesting just ended it.","CSS has supported nesting natively since 2023 — pseudo-classes, pseudo-elements, and @media queries nested inside the rules they belong to. No compiler required.","\u002Fmedia\u002Fcovers\u002Fcss-nesting-sass-replaced.png","2026-07-09T09:48:41.505Z",389,{"id":57,"name":58,"username":59,"avatarUrl":50,"headline":60},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":97,"name":151},"CSS",[153,154,155,156],{"slug":97,"name":98,"color":50},{"slug":69,"name":70,"color":50},{"slug":72,"name":73,"color":50},{"slug":63,"name":67,"color":50},{"assessments":78},{"slug":142},{"id":160,"slug":161,"title":162,"subtitle":50,"excerpt":163,"coverUrl":164,"locale":13,"readingMinutes":53,"publishedAt":165,"viewCount":166,"likeCount":19,"commentCount":19,"author":167,"vertical":168,"topic":169,"tags":170,"_count":175,"playground":176,"hasQuiz":17,"hasPlayground":17},"019fe65f-f67a-7038-9c0d-874d6c8ece3c","css-property-registered-custom-properties","You can't transition a CSS variable. @property says otherwise.","CSS custom properties are string substitution — the browser doesn't know a number from a color. Register one with @property and it gains a real type, an initial value, and the ability to animate.","\u002Fmedia\u002Fcovers\u002Fcss-property-registered-custom-properties.png","2026-07-08T08:36:23.824Z",614,{"id":57,"name":58,"username":59,"avatarUrl":50,"headline":60},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":97,"name":151},[171,172,173,174],{"slug":97,"name":98,"color":50},{"slug":69,"name":70,"color":50},{"slug":72,"name":73,"color":50},{"slug":63,"name":67,"color":50},{"assessments":78},{"slug":161},{"id":178,"slug":179,"title":180,"subtitle":50,"excerpt":181,"coverUrl":182,"locale":13,"readingMinutes":183,"publishedAt":184,"viewCount":185,"likeCount":19,"commentCount":19,"author":186,"vertical":187,"topic":188,"tags":189,"_count":194,"playground":195,"hasQuiz":17,"hasPlayground":17},"019fe65f-ef22-765a-97c7-cdfdbb168024","scroll-driven-animations","Your scroll listener is doing CSS's job","Reading progress bars, reveal-on-scroll effects, parallax — you've been writing these in JavaScript. CSS scroll-driven animations bind them directly to scroll position, off the main thread, in a handful of lines.","\u002Fmedia\u002Fcovers\u002Fscroll-driven-animations.png",6,"2026-07-06T10:47:02.014Z",455,{"id":57,"name":58,"username":59,"avatarUrl":50,"headline":60},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":97,"name":151},[190,191,192,193],{"slug":97,"name":98,"color":50},{"slug":69,"name":70,"color":50},{"slug":72,"name":73,"color":50},{"slug":63,"name":67,"color":50},{"assessments":78},{"slug":179},{"id":197,"slug":198,"title":199,"subtitle":50,"excerpt":200,"coverUrl":201,"locale":13,"readingMinutes":86,"publishedAt":202,"viewCount":203,"likeCount":19,"commentCount":19,"author":204,"vertical":205,"topic":206,"tags":207,"_count":214,"playground":50,"hasQuiz":18,"hasPlayground":18},"019fe65f-e7b8-7175-a185-34775c370bcf","abort-controller-async-cancellation","Your fetch() Is Still Running After the User Left","Stale requests, race conditions in search boxes, state updates on unmounted components — these are all the same bug: async work you forgot to cancel. AbortController is the fix.","\u002Fmedia\u002Fcovers\u002Fabort-controller-async-cancellation.png","2026-07-05T09:12:47.873Z",319,{"id":57,"name":58,"username":59,"avatarUrl":50,"headline":60},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":63,"name":64},[208,209,210,211],{"slug":63,"name":67,"color":50},{"slug":69,"name":70,"color":50},{"slug":72,"name":73,"color":50},{"slug":212,"name":213,"color":50},"react","React",{"assessments":19},{"id":216,"slug":217,"title":218,"subtitle":50,"excerpt":219,"coverUrl":220,"locale":13,"readingMinutes":53,"publishedAt":221,"viewCount":222,"likeCount":19,"commentCount":19,"author":223,"vertical":224,"topic":225,"tags":226,"_count":231,"playground":50,"hasQuiz":18,"hasPlayground":18},"019fe65f-e05c-77bb-b8a3-cb8dbdc99346","css-layer-architecture","You reached for !important again. @layer is the real fix.","When a third-party reset beats your styles and your own utilities lose to an ancient nested rule, the problem isn't your selectors. It's that your stylesheet has no architecture. @layer adds one.","\u002Fmedia\u002Fcovers\u002Fcss-layer-architecture.png","2026-07-04T08:44:02.193Z",175,{"id":57,"name":58,"username":59,"avatarUrl":50,"headline":60},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":97,"name":151},[227,228,229,230],{"slug":97,"name":98,"color":50},{"slug":69,"name":70,"color":50},{"slug":72,"name":73,"color":50},{"slug":63,"name":67,"color":50},{"assessments":19},{"id":233,"slug":234,"title":235,"subtitle":50,"excerpt":236,"coverUrl":237,"locale":13,"readingMinutes":53,"publishedAt":238,"viewCount":239,"likeCount":19,"commentCount":19,"author":240,"vertical":241,"topic":242,"tags":243,"_count":248,"playground":50,"hasQuiz":18,"hasPlayground":18},"019fe65f-d8d6-73ed-b26b-18726a494914","view-transitions-native-page-transitions","The page transition you pay a library for is now free","You reach for Framer Motion or GSAP to make navigation feel smooth. The View Transitions API does the same thing natively — and the starting price is a single CSS rule.","\u002Fmedia\u002Fcovers\u002Fview-transitions-native-page-transitions.png","2026-07-03T09:26:36.534Z",187,{"id":57,"name":58,"username":59,"avatarUrl":50,"headline":60},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":97,"name":151},[244,245,246,247],{"slug":97,"name":98,"color":50},{"slug":69,"name":70,"color":50},{"slug":72,"name":73,"color":50},{"slug":63,"name":67,"color":50},{"assessments":19},{"id":250,"slug":251,"title":252,"subtitle":50,"excerpt":253,"coverUrl":254,"locale":13,"readingMinutes":86,"publishedAt":255,"viewCount":256,"likeCount":19,"commentCount":19,"author":257,"vertical":258,"topic":259,"tags":260,"_count":265,"playground":50,"hasQuiz":18,"hasPlayground":18},"019fe65f-d19a-709a-855e-54178d886feb","has-selector-condition-evaluator",":has() isn't a parent selector. It deletes JavaScript.","Everyone calls :has() the parent selector. That framing is too small — it's a condition evaluator that obsoletes a whole category of class-toggling JS, and it's in every browser today.","\u002Fmedia\u002Fcovers\u002Fhas-selector-condition-evaluator.png","2026-07-02T07:18:03.500Z",235,{"id":57,"name":58,"username":59,"avatarUrl":50,"headline":60},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":97,"name":151},[261,262,263,264],{"slug":97,"name":98,"color":50},{"slug":69,"name":70,"color":50},{"slug":72,"name":73,"color":50},{"slug":63,"name":67,"color":50},{"assessments":19},{"id":267,"slug":268,"title":269,"subtitle":50,"excerpt":270,"coverUrl":271,"locale":13,"readingMinutes":86,"publishedAt":272,"viewCount":273,"likeCount":19,"commentCount":19,"author":274,"vertical":275,"topic":276,"tags":277,"_count":282,"playground":50,"hasQuiz":18,"hasPlayground":18},"019fe65f-c9aa-70db-8ac8-df39bed8061b","optimistic-updates-stop-waiting-for-the-server","Optimistic Updates: Stop Making Your Save Button Wait for the Server","Every click that spins for a server round-trip is a choice you made. Optimistic updates remove the wait — but the rollback is where almost every implementation quietly breaks.","\u002Fmedia\u002Fcovers\u002Foptimistic-updates-stop-waiting-for-the-server.png","2026-07-01T07:42:41.462Z",251,{"id":57,"name":58,"username":59,"avatarUrl":50,"headline":60},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":63,"name":64},[278,279,280,281],{"slug":69,"name":70,"color":50},{"slug":72,"name":73,"color":50},{"slug":63,"name":67,"color":50},{"slug":212,"name":213,"color":50},{"assessments":19},{"page":284,"perPage":285,"total":286,"totalPages":287},14,12,174,15,[289,290,292,294,298,300,304,306,308,312,316,318,321,325,329,332,336,340,343,346,350,353,356,359,362,365,368,371,374,377,380,383,386,389,392,395,398,401,404,407],{"slug":69,"name":70,"color":50,"articles":286},{"slug":63,"name":67,"color":50,"articles":291},141,{"slug":72,"name":73,"color":50,"articles":293},96,{"slug":295,"name":296,"color":50,"articles":297},"tutorial","Tutorial",71,{"slug":97,"name":98,"color":50,"articles":299},51,{"slug":301,"name":302,"color":50,"articles":303},"performance","Performance",30,{"slug":112,"name":116,"color":50,"articles":305},25,{"slug":212,"name":213,"color":50,"articles":307},20,{"slug":309,"name":310,"color":50,"articles":311},"programming","Programming",19,{"slug":313,"name":314,"color":50,"articles":315},"browser","Browser",18,{"slug":75,"name":76,"color":50,"articles":317},16,{"slug":319,"name":320,"color":50,"articles":285},"html","Html",{"slug":322,"name":323,"color":50,"articles":324},"nextjs","Nextjs",11,{"slug":326,"name":327,"color":50,"articles":328},"vue","Vue",10,{"slug":330,"name":331,"color":50,"articles":328},"accessibility","Accessibility",{"slug":333,"name":334,"color":50,"articles":335},"nestjs","Nestjs",9,{"slug":337,"name":338,"color":50,"articles":339},"nuxt","Nuxt",8,{"slug":341,"name":342,"color":50,"articles":339},"career","Career",{"slug":344,"name":345,"color":50,"articles":339},"discuss","Discuss",{"slug":347,"name":348,"color":50,"articles":349},"beginners","Beginners",7,{"slug":351,"name":352,"color":50,"articles":349},"productivity","Productivity",{"slug":354,"name":355,"color":50,"articles":183},"grammar","Grammar",{"slug":357,"name":358,"color":50,"articles":53},"security","Security",{"slug":360,"name":361,"color":50,"articles":86},"ssr","SSR",{"slug":363,"name":364,"color":50,"articles":86},"apis","Apis",{"slug":366,"name":367,"color":50,"articles":43},"ai","Ai",{"slug":369,"name":370,"color":50,"articles":43},"api","API",{"slug":372,"name":373,"color":50,"articles":43},"caching","Caching",{"slug":375,"name":376,"color":50,"articles":31},"async","Async",{"slug":378,"name":379,"color":50,"articles":31},"forms","Forms",{"slug":381,"name":382,"color":50,"articles":31},"dom","Dom",{"slug":384,"name":385,"color":50,"articles":31},"backend","Backend",{"slug":387,"name":388,"color":50,"articles":31},"english","English",{"slug":390,"name":391,"color":50,"articles":31},"verbs","Verbs",{"slug":393,"name":394,"color":50,"articles":31},"spanish","Spanish",{"slug":396,"name":397,"color":50,"articles":31},"a1","A1",{"slug":399,"name":400,"color":50,"articles":31},"a2","A2",{"slug":402,"name":403,"color":50,"articles":31},"tenses","Tenses",{"slug":405,"name":406,"color":50,"articles":31},"turkish","Turkish",{"slug":408,"name":409,"color":50,"articles":31},"animation","Animation",[411,412,413,414,415,416,417,418,419,420,421,422],{"slug":69,"name":70,"articles":286},{"slug":63,"name":67,"articles":291},{"slug":72,"name":73,"articles":293},{"slug":295,"name":296,"articles":297},{"slug":97,"name":98,"articles":299},{"slug":301,"name":302,"articles":303},{"slug":112,"name":116,"articles":305},{"slug":212,"name":213,"articles":307},{"slug":309,"name":310,"articles":311},{"slug":313,"name":314,"articles":315},{"slug":75,"name":76,"articles":317},{"slug":319,"name":320,"articles":285}]