[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"verticals":3,"tag-webdev-4":32,"tags-dev":266},[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":263},[34,68,87,105,125,142,159,176,192,208,224,241],{"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},"019fe65f-fe39-767c-9ce8-da4db5144b1d","css-nesting-sass-replaced","You kept Sass for one reason. Native CSS nesting just ended it.",null,"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",4,"2026-07-09T09:48:41.505Z",41,{"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":74,"publishedAt":75,"viewCount":76,"likeCount":19,"commentCount":19,"author":77,"vertical":78,"topic":79,"tags":80,"_count":85,"playground":86,"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",5,"2026-07-08T08:36:23.824Z",53,{"id":45,"name":46,"username":47,"avatarUrl":38,"headline":48},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":51,"name":52},[81,82,83,84],{"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":70},{"id":88,"slug":89,"title":90,"subtitle":38,"excerpt":91,"coverUrl":92,"locale":13,"readingMinutes":74,"publishedAt":93,"viewCount":94,"likeCount":19,"commentCount":19,"author":95,"vertical":96,"topic":97,"tags":98,"_count":103,"playground":104,"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","2026-07-06T10:47:02.014Z",48,{"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":63,"name":64,"color":38},{"assessments":66},{"slug":89},{"id":106,"slug":107,"title":108,"subtitle":38,"excerpt":109,"coverUrl":110,"locale":13,"readingMinutes":41,"publishedAt":111,"viewCount":112,"likeCount":19,"commentCount":19,"author":113,"vertical":114,"topic":115,"tags":117,"_count":124,"playground":38,"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",6,{"id":45,"name":46,"username":47,"avatarUrl":38,"headline":48},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":63,"name":116},"JavaScript",[118,119,120,121],{"slug":63,"name":64,"color":38},{"slug":57,"name":58,"color":38},{"slug":60,"name":61,"color":38},{"slug":122,"name":123,"color":38},"react","React",{"assessments":19},{"id":126,"slug":127,"title":128,"subtitle":38,"excerpt":129,"coverUrl":130,"locale":13,"readingMinutes":74,"publishedAt":131,"viewCount":132,"likeCount":19,"commentCount":19,"author":133,"vertical":134,"topic":135,"tags":136,"_count":141,"playground":38,"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",8,{"id":45,"name":46,"username":47,"avatarUrl":38,"headline":48},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":51,"name":52},[137,138,139,140],{"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":19},{"id":143,"slug":144,"title":145,"subtitle":38,"excerpt":146,"coverUrl":147,"locale":13,"readingMinutes":74,"publishedAt":148,"viewCount":149,"likeCount":19,"commentCount":19,"author":150,"vertical":151,"topic":152,"tags":153,"_count":158,"playground":38,"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",10,{"id":45,"name":46,"username":47,"avatarUrl":38,"headline":48},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":51,"name":52},[154,155,156,157],{"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":19},{"id":160,"slug":161,"title":162,"subtitle":38,"excerpt":163,"coverUrl":164,"locale":13,"readingMinutes":41,"publishedAt":165,"viewCount":166,"likeCount":19,"commentCount":19,"author":167,"vertical":168,"topic":169,"tags":170,"_count":175,"playground":38,"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",7,{"id":45,"name":46,"username":47,"avatarUrl":38,"headline":48},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":51,"name":52},[171,172,173,174],{"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":19},{"id":177,"slug":178,"title":179,"subtitle":38,"excerpt":180,"coverUrl":181,"locale":13,"readingMinutes":41,"publishedAt":182,"viewCount":132,"likeCount":19,"commentCount":19,"author":183,"vertical":184,"topic":185,"tags":186,"_count":191,"playground":38,"hasQuiz":18,"hasPlayground":18},"019fe65f-c9aa-70db-8ac8-df39bed8061b","optimistic-updates-stop-waiting-for-the-server","Your Save button waits 300ms for nothing. Stop it.","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",{"id":45,"name":46,"username":47,"avatarUrl":38,"headline":48},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":63,"name":116},[187,188,189,190],{"slug":57,"name":58,"color":38},{"slug":60,"name":61,"color":38},{"slug":63,"name":64,"color":38},{"slug":122,"name":123,"color":38},{"assessments":19},{"id":193,"slug":194,"title":195,"subtitle":38,"excerpt":196,"coverUrl":197,"locale":13,"readingMinutes":41,"publishedAt":198,"viewCount":166,"likeCount":19,"commentCount":19,"author":199,"vertical":200,"topic":201,"tags":202,"_count":207,"playground":38,"hasQuiz":18,"hasPlayground":18},"019fe65f-c193-7159-96ba-bff62b34e53d","container-queries-responsive-primitive","Your card breaks in the sidebar. Here's the real fix.","A component that looks perfect in the main column falls apart in a sidebar — and the viewport width says everything's fine. The bug isn't your CSS. It's the question your CSS is asking.","\u002Fmedia\u002Fcovers\u002Fcontainer-queries-responsive-primitive.png","2026-06-30T07:30:01.218Z",{"id":45,"name":46,"username":47,"avatarUrl":38,"headline":48},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":51,"name":52},[203,204,205,206],{"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":19},{"id":209,"slug":210,"title":211,"subtitle":38,"excerpt":212,"coverUrl":213,"locale":13,"readingMinutes":41,"publishedAt":214,"viewCount":74,"likeCount":19,"commentCount":19,"author":215,"vertical":216,"topic":217,"tags":218,"_count":223,"playground":38,"hasQuiz":18,"hasPlayground":18},"019fe65f-b9de-72a8-8656-ee81360dbd99","url-as-state-manager","The URL Is Your Best State Manager","You're storing filter state, search queries, and pagination in useState — and losing it every time someone refreshes. The URL already does this better.","\u002Fmedia\u002Fcovers\u002Furl-as-state-manager.png","2026-06-29T07:59:09.726Z",{"id":45,"name":46,"username":47,"avatarUrl":38,"headline":48},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":63,"name":116},[219,220,221,222],{"slug":57,"name":58,"color":38},{"slug":60,"name":61,"color":38},{"slug":63,"name":64,"color":38},{"slug":122,"name":123,"color":38},{"assessments":19},{"id":225,"slug":226,"title":227,"subtitle":38,"excerpt":228,"coverUrl":229,"locale":13,"readingMinutes":230,"publishedAt":231,"viewCount":132,"likeCount":19,"commentCount":19,"author":232,"vertical":233,"topic":234,"tags":235,"_count":240,"playground":38,"hasQuiz":18,"hasPlayground":18},"019fe65f-b1ba-7644-b327-4118cffd7d22","server-components-mental-model","Server Components Without the Hype: A Mental Model That Sticks","RSC isn't 'SSR 2.0' and it isn't magic. Here's the one distinction that makes the whole model click.","\u002Fmedia\u002Fcovers\u002Fserver-components-mental-model.png",3,"2026-06-28T09:41:35.140Z",{"id":45,"name":46,"username":47,"avatarUrl":38,"headline":48},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":122,"name":123},[236,237,238,239],{"slug":122,"name":123,"color":38},{"slug":57,"name":58,"color":38},{"slug":60,"name":61,"color":38},{"slug":63,"name":64,"color":38},{"assessments":19},{"id":242,"slug":243,"title":244,"subtitle":38,"excerpt":245,"coverUrl":246,"locale":13,"readingMinutes":230,"publishedAt":247,"viewCount":248,"likeCount":19,"commentCount":19,"author":249,"vertical":250,"topic":251,"tags":254,"_count":262,"playground":38,"hasQuiz":18,"hasPlayground":18},"019fe65f-a9f9-7079-bfbf-ca4dc5685bdd","typescript-won-what-it-bought-us","TypeScript Won. Here's What That Actually Bought Us.","The 'should we use TypeScript?' debate is over. The interesting question is what all those types are quietly enabling now.","\u002Fmedia\u002Fcovers\u002Ftypescript-won-what-it-bought-us.png","2026-06-28T07:31:54.189Z",11,{"id":45,"name":46,"username":47,"avatarUrl":38,"headline":48},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":252,"name":253},"typescript","TypeScript",[255,257,258,259],{"slug":252,"name":256,"color":38},"Typescript",{"slug":63,"name":64,"color":38},{"slug":57,"name":58,"color":38},{"slug":260,"name":261,"color":38},"ai","Ai",{"assessments":19},{"page":41,"perPage":264,"total":265,"totalPages":74},12,50,[267,268,270,272,274,276,279,280,283,284,287],{"slug":57,"name":58,"color":38,"articles":265},{"slug":63,"name":64,"color":38,"articles":269},45,{"slug":60,"name":61,"color":38,"articles":271},44,{"slug":51,"name":55,"color":38,"articles":273},18,{"slug":252,"name":256,"color":38,"articles":275},9,{"slug":277,"name":278,"color":38,"articles":166},"performance","Performance",{"slug":122,"name":123,"color":38,"articles":74},{"slug":281,"name":282,"color":38,"articles":41},"node","Node",{"slug":260,"name":261,"color":38,"articles":230},{"slug":285,"name":286,"color":38,"articles":230},"tutorial","Tutorial",{"slug":288,"name":289,"color":38,"articles":230},"html","Html"]