[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"contentNavigation":3,"newsletter-stats":4,"$fQa3xUpnRDPNiFFu2QS4K-DAjYmsapeR9fNhPNBdpkOc":-1,"topic-ui-components":6,"articles-feed-\u002Ftopics\u002Fui-components-1-ui-components-":11,"home-tags":131},[],{"confirmedCount":5},405,{"articleCount":7,"color":8,"id":9,"name":10,"slug":10},5,"#10b981","019d6bd8-ca8b-709c-b9a5-77d4910da162","ui-components",{"items":12,"page":129,"pageSize":130,"totalCount":7},[13,37,65,87,108],{"content":14,"createdAt":15,"id":16,"image":17,"isAffiliate":18,"isPublished":18,"publishedAt":19,"slug":20,"sourceId":21,"sourceName":22,"sourceType":23,"summary":24,"title":25,"updatedAt":26,"url":27,"urlHash":28,"tags":29},"A hands-on walkthrough of TresJS, the Vue custom renderer for Three.js. From a blank canvas to a reactive 3D scene.","2026-06-16T16:11:23.030Z","019ed133-a3ff-777b-adc9-d4611efcce78","https:\u002F\u002Fapi.certificates.dev\u002Fstorage\u002FJzzmU8odS8xTY4oUOFA5dKGDUZ9t1KTrC32UQtOD.png",true,"2026-06-10T06:00:00.000Z","building-3d-scenes-with-tresjs","019d9eed-d835-729a-a029-7e6320cb67ed","Certificates.dev","certificatesdev","This article provides a hands-on guide to using TresJS, a Vue custom renderer for Three.js, to create reactive 3D scenes. It walks through the process from starting with a blank canvas to building interactive 3D visuals.","Building 3D Scenes with TresJS","2026-06-16T16:11:31.024Z","https:\u002F\u002Fcertificates.dev\u002Fblog\u002Fbuilding-3d-scenes-with-tresjs?friend=MOKKAPPS","2e1b1561dca4ab364f3836c76e19030b82096d6ba565f6dc48db6e10c7ad2f55",[30,33,36],{"color":8,"id":31,"name":32,"slug":32},"019d6bd8-c9a8-7783-bd22-03145b355427","vue",{"color":8,"id":34,"name":35,"slug":35},"019ed133-c390-75bf-8f1a-5c57cd221f14","threejs",{"color":8,"id":9,"name":10,"slug":10},{"content":38,"createdAt":39,"id":40,"image":41,"isAffiliate":42,"isPublished":18,"publishedAt":43,"slug":44,"sourceId":45,"sourceName":46,"sourceType":47,"summary":48,"title":49,"updatedAt":50,"url":51,"urlHash":52,"tags":53},"Animations can make an application feel faster, smoother, and more polished. However, many developers think animations are only useful for things like: page transitions modals enter\u002Fleave effects But Vue provides another powerful pattern - State-driven animations. Instead of animating when elements are added or removed from the DOM, you animate changes in reactive state. This allows you to create rich interactive experiences while keeping your code declarative and easy to maintain. In this article, we'll explore: What state-driven animations are How they differ from regular Vue transitions What problems they solve How to implement them in Vue Best practices for creating smooth UI interactions Let's dive in. 🤔 What Are State-Driven Animations? Most Vue developers are familiar with the &lt;Transition&gt; component. Example: &lt;Transition&gt; &lt;Modal v-if=\"isOpen\" \u002F&gt; &lt;\u002FTransition&gt; This animates an element when it enters or leaves the DOM. But what if the element already exists and only its state changes? For example: a progress bar grows a card expands a chart updates a panel changes size a value changes position This is where state-driven animations shine. Instead of animating DOM insertion or removal, you animate changes caused by reactive state. 🟢 What Problem Do State-Driven Animations Solve? Without animations, state changes can feel abrupt. Example: &lt;div :style=\"{ width: progress + '%' }\"&gt;&lt;\u002Fdiv&gt; When progress changes: progress.value = 80 The width instantly jumps. This works technically... but it doesn't feel great. 🟢 A Simple Example Let's create an animated progress bar. &lt;script setup lang=\"ts\"&gt; const progress = ref(20) function increase() { progress.value += 20 } &lt;\u002Fscript&gt; &lt;template&gt; &lt;button @click=\"increase\"&gt; Increase Progress &lt;\u002Fbutton&gt; &lt;div class=\"progress-container\"&gt; &lt;div class=\"progress-bar\" :style=\"{ width: `${progress}%` }\" \u002F&gt; &lt;\u002Fdiv&gt; &lt;\u002Ftemplate&gt; CSS: .progress-container { width: 100%; height: 12px; background: #eee; } .progress-bar { height: 100%; background: #42b883; transition: width 0.3s ease; } Now whenever progress changes, the bar animates smoothly. The animation is entirely driven by reactive state. 🟢 Animating Multiple Properties State-driven animations are not limited to width. Example: &lt;div class=\"card\" :style=\"{ transform: expanded ? 'scale(1.1)' : 'scale(1)', opacity: expanded ? 1 : 0.7 }\" \u002F&gt; CSS: .card { transition: transform 0.3s ease, opacity 0.3s ease; } Now changing: expanded.value = true animates scale and opacity at the same time. 🟢 Using Vue Reactivity with Animations One of the biggest advantages is that animations stay connected to Vue's reactivity system. Example: &lt;script setup lang=\"ts\"&gt; const isActive = ref(false) &lt;\u002Fscript&gt; &lt;template&gt; &lt;button @click=\"isActive = !isActive\"&gt; Toggle &lt;\u002Fbutton&gt; &lt;div class=\"box\" :class=\"{ active: isActive }\" \u002F&gt; &lt;\u002Ftemplate&gt; CSS: .box { width: 100px; height: 100px; transition: all 0.4s ease; } .box.active { transform: rotate(180deg); } Vue handles state. CSS handles animation. The result is clean and maintainable. 🧪 Best Practices Keep animations subtle and purposeful Prefer CSS transitions for simple effects Avoid animating expensive properties when possible Use transforms instead of layout-changing properties when appropriate Don't animate everything Keep durations short (typically 200–400ms) Use animations to communicate state changes, not distract users 📖 Learn more If you would like to learn more about Vue, Nuxt, JavaScript or other useful technologies, checkout VueSchool by clicking this link or by clicking the image below: It covers most important concepts while building modern Vue or Nuxt applications that can help you in your daily work or side projects 😉 🧪 Advance skills A certification boosts your skills, builds credibility, and opens doors to new opportunities. Whether you're advancing your career or switching paths, it's a smart step toward success. Check out Certificates.dev by clicking this link or by clicking the image below: Invest in yourself—get certified in Vue.js, JavaScript, Nuxt, Angular, React, and more! ✅ Summary State-driven animations are a powerful way to create smooth and engaging user experiences in Vue. While &lt;Transition&gt; is perfect for entering and leaving elements, state-driven animations excel when existing elements need to react smoothly to changing data. Used thoughtfully, they can make your applications feel significantly more responsive and professional. Take care! And happy coding as always 🖥️","2026-06-01T12:00:05.566Z","019e830e-2fa7-74ed-8c74-71fc2c69cb52","https:\u002F\u002Fmedia2.dev.to\u002Fdynamic\u002Fimage\u002Fwidth=1200,height=627,fit=cover,gravity=auto,format=auto\u002Fhttps%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvih3y2fdc8upo7ni9m42.png",false,"2026-06-01T09:54:37.000Z","state-driven-animations-in-vue-create-smooth-ui-transitions-with-reactive-state","019d6bd6-7fe0-7244-80dc-9a4e8751886a","Jakub Andrzejewski","rss","This article explores state-driven animations in Vue, highlighting how they enhance UI transitions by animating changes in reactive state rather than just DOM insertion or removal. It provides examples and best practices for implementing these animations to create smoother, more interactive user experiences.","State-Driven Animations in Vue: Create Smooth UI Transitions with Reactive State","2026-06-10T14:35:13.767Z","https:\u002F\u002Fdev.to\u002Fjacobandrewsky\u002Fstate-driven-animations-in-vue-create-smooth-ui-transitions-with-reactive-state-d3i","b6046ff3585c584d9e28b56411b296d962249089895ddbb6902902fabcfdafec",[54,55,58,61,62],{"color":8,"id":31,"name":32,"slug":32},{"color":8,"id":56,"name":57,"slug":57},"019e830e-5378-722b-929b-a57d67bcf605","animation",{"color":8,"id":59,"name":60,"slug":60},"019daac3-2f85-7393-b891-9da3891267ca","reactivity",{"color":8,"id":9,"name":10,"slug":10},{"color":8,"id":63,"name":64,"slug":64},"019d6bd8-fba5-743f-8f9f-4e23c0b31581","tutorial",{"content":66,"createdAt":67,"id":68,"image":69,"isAffiliate":42,"isPublished":18,"publishedAt":70,"slug":71,"sourceId":72,"sourceName":73,"sourceType":47,"summary":74,"title":75,"updatedAt":76,"url":77,"urlHash":78,"tags":79},"Our own AI agent on nuxt.com, grounded in the official docs and the Nuxt ecosystem. We built it internally using the AI SDK, our MCP server, and Nuxt UI components.","2026-04-30T04:18:55.740Z","019ddc9c-7a6a-76a8-8ec2-038b607968be","https:\u002F\u002Fnuxt.com\u002Fnuxt-agent.jpg","2026-04-29T00:00:00.000Z","introducing-the-nuxt-agent","019d6c1a-e19c-736e-b489-240be1c0d29a","Nuxt Blog","The article introduces the Nuxt Agent, an AI tool developed for nuxt.com that utilizes the official documentation and the Nuxt ecosystem. It was created using the AI SDK, MCP server, and Nuxt UI components.","Introducing the Nuxt Agent","2026-04-30T04:19:02.005Z","https:\u002F\u002Fnuxt.com\u002Fblog\u002Fintroducing-nuxt-agent","b10cc6b9333ffa6506fbfa0656387e9b83b8ee921c06c62bb137df8da05cd754",[80,83,84],{"color":8,"id":81,"name":82,"slug":82},"019d6bd8-fad3-70a9-a74d-ab96e3a2f45d","nuxt",{"color":8,"id":9,"name":10,"slug":10},{"color":8,"id":85,"name":86,"slug":86},"019d9d20-e07b-7685-9ebb-fae0b963f243","ai",{"content":88,"createdAt":89,"id":90,"image":91,"isAffiliate":42,"isPublished":18,"publishedAt":92,"slug":93,"sourceId":94,"sourceName":95,"sourceType":96,"summary":97,"title":98,"updatedAt":99,"url":100,"urlHash":101,"tags":102},"As AI agents are becoming active “users” of your software, they must learn to interact with complex UIs safely and effectively.","2026-04-17T19:35:11.345Z","019d9cf0-aadb-7522-87ac-a1a8baea8eb5","https:\u002F\u002Fi.ytimg.com\u002Fvi\u002FkR2GHGPLxSM\u002Fhqdefault.jpg","2026-04-16T10:00:06.000Z","rijk-van-zanten---guiding-agentic-ai-with-vue-and-pinia","019d9ce0-e8f2-774a-ba57-a61c19469fe1","Vuejs Amsterdam","youtube","The article discusses the integration of agentic AI with user interfaces built using Vue and Pinia, emphasizing the importance of guiding AI agents to interact with complex UIs safely and effectively.","Rijk van Zanten - Guiding Agentic AI with Vue and Pinia","2026-04-17T19:35:19.243Z","https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=kR2GHGPLxSM","b66757cbea3dae368d5c7fe2c3ee86b47b67c447471c2e6c144211d306503518",[103,104,107],{"color":8,"id":31,"name":32,"slug":32},{"color":8,"id":105,"name":106,"slug":106},"019d9cf0-c9de-70b2-9057-76d771c3379e","pinia",{"color":8,"id":9,"name":10,"slug":10},{"content":109,"createdAt":110,"id":111,"image":112,"isAffiliate":18,"isPublished":18,"publishedAt":113,"slug":114,"sourceId":115,"sourceName":116,"sourceType":117,"summary":118,"title":119,"updatedAt":120,"url":121,"urlHash":122,"tags":123},"If you have ever built a chat thread, card feed, whiteboard label editor, or masonry layout in Vue, you have probably ended up doing something slightly gross: render text into the DOM, measure it, and then rerender or reposition everything based on that measurement. That works, but it comes with baggage: hidden measurement nodes getBoundingClientRect() and offsetHeight reads in hot paths resize loops that mix layout and app state virtualization code that needs a height before the row is even mounted Pretext is interesting because it attacks that exact problem. Instead of asking the DOM how tall wrapped text became, it prepares the text once and then lays it out against a width using cached measurements. In other words, you can know a text's height before it is even mounted so that Vue can stay focused on state and rendering while Pretext handles the text math. This is not a replacement for Vue, CSS, or the browser layout engine. It is a way to stop using the DOM as your text calculator when all you really need is line count and height. 👉 Don't quite follow? Check out the demo. It breaks down things visually for you. What Pretext actually does The core model is simple: prepare(text, font) does the expensive work once. layout(prepared, width, lineHeight) returns the wrapped height and line count for that width. That split matters. If the text and font stay the same while the available width changes, you do not need to re-measure every grapheme from scratch on every resize. You reuse the prepared value and run layout again. That makes Pretext especially compelling in UI that has lots of text blocks with widths changing over time: virtualized feeds resizable sidebars draggable canvases with labels shrink-wrapped chat bubbles card grids where item height depends on text The Vue angle Vue is already very good at state transitions. The problem is that text measurement traditionally drags you back into imperative DOM work. You start with clean reactive code: const messages = ref&lt;Message[]&gt;([]); Then layout requirements show up and suddenly you are doing things like: await nextTick(); const height = node.getBoundingClientRect().height; That is the line I would try to delete first. With Pretext, the flow looks more like this: Vue owns the text, width, and rendering state. Pretext derives height and line count from text plus width. Your list, grid, or canvas logic consumes those numbers without mounting probe elements first. That is a much cleaner separation of concerns. Install it ni @chenglou\u002Fpretext A simple Vue composable The main trick is to make prepare() depend on the text and font, but not the width. Width changes should only trigger layout(). import { computed, toValue } from &quot;vue&quot;; import { layout, prepare } from &quot;@chenglou\u002Fpretext&quot;; export function usePretextLayout(options) { const text = computed(() =&gt; toValue(options.text)); const font = computed(() =&gt; toValue(options.font)); const width = computed(() =&gt; toValue(options.width)); const lineHeight = computed(() =&gt; toValue(options.lineHeight)); const prepared = computed(() =&gt; prepare(text.value, font.value)); const result = computed(() =&gt; layout(prepared.value, Math.max(1, width.value), lineHeight.value), ); const height = computed(() =&gt; result.value.height); const lineCount = computed(() =&gt; result.value.lineCount); return { text, font, width, lineHeight, prepared, result, height, lineCount, }; } Why split it this way? Text changes should invalidate the prepared measurement. Font changes should also invalidate it. Width changes should only rerun layout. That maps nicely onto Vue's computed graph. Use it in a component Here is a minimal card example. The width is reactive, but the text measurement does not require mounting a hidden probe element just to discover its height. &lt;script setup lang=&quot;ts&quot;&gt; import { ref } from &quot;vue&quot;; import { usePretextLayout } from &quot;.\u002Fcomposables\u002FusePretextLayout&quot;; const body = ref( &quot;Pretext lets Vue apps estimate wrapped text height without measuring hidden DOM nodes first.&quot;, ); const cardWidth = ref(320); const font = ref(&quot;400 16px Inter, system-ui, sans-serif&quot;); const lineHeight = ref(24); const { height, lineCount } = usePretextLayout({ text: body, font, width: cardWidth, lineHeight, }); &lt;\u002Fscript&gt; &lt;template&gt; &lt;article class=&quot;card&quot; :style=&quot;{ width: `${cardWidth}px` }&quot;&gt; &lt;p&gt;{{ body }}&lt;\u002Fp&gt; &lt;footer&gt;{{ lineCount }} lines, {{ height }}px tall&lt;\u002Ffooter&gt; &lt;\u002Farticle&gt; &lt;\u002Ftemplate&gt; This is the important mindset shift: the card height is no longer something you discover after the browser lays out the paragraph. It is something you can derive from the same reactive inputs that already describe the UI. Where this gets really useful The simplest demo is a single card, but that is not where the real value is. The real value shows up when the old approach creates layout thrash or architectural awkwardness. 1. Virtualized lists with variable-height text Virtualization loves predictable heights. Text-heavy UIs often do not have them. Pretext gives you a better story: prepare message text when data arrives compute row height from the current column width feed that height into your virtualizer rerun layout when the list width changes That is much better than mounting off-screen rows just to measure them. import { layout, prepare, type PreparedText } from &quot;@chenglou\u002Fpretext&quot;; type Row = { id: string; body: string; prepared: PreparedText; }; const font = &quot;400 15px Inter, system-ui, sans-serif&quot;; const lineHeight = 22; const rows: Row[] = apiRows.map((row) =&gt; ({ id: row.id, body: row.body, prepared: prepare(row.body, font), })); function getRowHeight(row: Row, contentWidth: number) { return layout(row.prepared, contentWidth, lineHeight).height + 24; } That pattern fits Vue very naturally. You can prepare once when rows are normalized, then derive heights wherever your layout logic needs them. 2. Chat bubbles that size to content If your message UI wants to make decisions based on line count or wrapped height, Pretext is a cleaner primitive than &quot;render first, inspect later.&quot; Examples: deciding whether a bubble gets compact or roomy chrome estimating whether a message should collapse behind &quot;show more&quot; aligning metadata differently for one-line versus multi-line messages Those are layout decisions based on text shape, not business logic. They should not require DOM probes in every component instance. 3. Canvas, whiteboards, and design tools This is where Pretext starts to feel like a category change rather than a small optimization. Its advanced APIs, including prepareWithSegments(), layoutWithLines(), and layoutNextLine(), are designed for cases where you need more than total height: drawing each wrapped line manually finding the widest produced line routing text line by line through changing widths That is useful for labels on canvases, text around shapes, or any UI where the browser is not directly painting the final text layout for you. A practical caveat: your font string has to match reality Pretext is not guessing in the abstract. It measures text against a font declaration and then lays out against a width and line height. That means two values need to match what your UI actually renders: the font string you pass to prepare() the lineHeight you pass to layout() If your component renders with a different font weight, font family, font size, or line height than the values you gave Pretext, your estimated result will drift from the actual DOM layout. So keep the typography source of truth tight. If the component uses: .message { font: 400 16px Inter, system-ui, sans-serif; line-height: 24px; } then your measurement inputs should match those values. What Pretext does not replace This is the part worth being explicit about, because the interesting thing about Pretext is not that it replaces everything. It replaces one very specific pain point. Pretext does not replace: Vue rendering CSS text styling actual width measurement of your container browser selection, caret behavior, or editing UX the browser's final paint of the real text node You still need a width from somewhere. Sometimes that is a prop. Sometimes it comes from your layout model. Sometimes a ResizeObserver is still appropriate. The difference is that you are no longer using the DOM to answer &quot;how tall did this paragraph become?&quot; That is a much smaller and cleaner dependency on layout. When I would reach for it I would consider Pretext when all of these are true: text height or line count affects layout decisions there are many text blocks, or the calculation happens often hidden measurement DOM is making the code awkward or slow you need the answer before mounting the final row or card I would probably not reach for it when: you are rendering a handful of static paragraphs CSS alone solves the problem you only need the browser to lay out the text once and never revisit it In other words, this is not &quot;replace CSS with a library.&quot; It is &quot;stop abusing the DOM as a calculator in text-heavy reactive UIs.&quot; The broader idea What makes Pretext interesting is not just the API. It is the shift in mental model. For a long time, web developers mostly accepted that wrapped text measurement had to be a DOM problem. Pretext challenges that assumption. In a Vue app, that means some layout decisions that used to live in nextTick(), probe elements, and measurement loops can move back into pure reactive derivation. That is exactly the kind of change I like: not because it is flashy, but because it removes a category of awkward code. Summary Pretext gives Vue developers a better option for text-heavy UI where height and line count matter. You prepare text once, lay it out against width as needed, and stop relying on hidden DOM nodes to tell you what wrapped text looks like.","2026-04-08T06:47:33.045Z","019d6bd8-a30c-720e-b82e-9253cd4d2970","https:\u002F\u002Fblog.vueschool.io\u002Fwp-content\u002Fuploads\u002F2026\u002F04\u002Ffeature-v2-1.jpg","2026-04-03T20:45:27.000Z","using-pretext-in-vue-to-build-variable-height-ui-without-layout-thrash","019d6bd5-87de-77ef-ac92-98aa56cda920","VueSchool","vueschool","The article discusses how to use Pretext in Vue to create variable-height UIs without the common pitfalls of layout thrashing. By preparing text measurements in advance, Pretext allows developers to avoid direct DOM manipulations for height calculations, leading to cleaner and more reactive code. This approach is particularly beneficial for UIs with dynamic text and changing widths.","Using Pretext in Vue to Build Variable-Height UI Without Layout Thrash","2026-04-08T06:47:42.561Z","https:\u002F\u002Fblog.vueschool.io\u002Fvuejs-tutorials\u002Fusing-pretext-in-vue-to-build-variable-height-ui-without-layout-thrash\u002F?friend=MOKKAPPS","75c6e75824a6e8739844c6c1bc511bbf6c5bc3302502ab9c9e1c87376385d07c",[124,125,128],{"color":8,"id":31,"name":32,"slug":32},{"color":8,"id":126,"name":127,"slug":127},"019d6bd8-ca26-775c-b9b5-c3439dbe5789","performance",{"color":8,"id":9,"name":10,"slug":10},1,20,{"tags":132},[133,138,142,145,149,151,156,160,164,168,172,176,181,185,189,193,197,201,205,209,213,217,221,225,229,233,237,241,245,249,253,257,261,265,269,273,277,281,285,289,293,297,301,305,309,313,317,321,325,329,333,337,341,345,349,353,357,361,365,369,373,377,380,384,388,392,396,400,404,407,411,413,417,421,425,429,431,435,439,443,447,451,455,459,463,467,471,475,480,484,488,492,496,500,504,508,510,514,517,521,522,526,530,534,538,542,546,550,553,557,561,566],{"articleCount":134,"color":8,"createdAt":135,"id":136,"name":137,"slug":137,"updatedAt":135},0,"2026-04-30T04:19:02.605Z","019ddc9c-954c-7703-8288-76d562fec577","accelerator",{"articleCount":129,"color":8,"createdAt":139,"id":140,"name":141,"slug":141,"updatedAt":139},"2026-04-08T06:47:43.120Z","019d6bd8-caef-76b9-bacd-363e31e6d2a9","accessibility",{"articleCount":143,"color":8,"createdAt":144,"id":85,"name":86,"slug":86,"updatedAt":144},8,"2026-04-17T20:27:50.780Z",{"articleCount":134,"color":8,"createdAt":146,"id":147,"name":148,"slug":148,"updatedAt":146},"2026-05-05T00:00:19.031Z","019df56f-8257-752e-a918-cdbb07c32b86","ai-agents",{"articleCount":129,"color":8,"createdAt":150,"id":56,"name":57,"slug":57,"updatedAt":150},"2026-06-01T12:00:14.713Z",{"articleCount":152,"color":8,"createdAt":153,"id":154,"name":155,"slug":155,"updatedAt":153},4,"2026-04-08T06:47:55.499Z","019d6bd8-fb46-77ef-a3b6-bd2d30ab8919","api",{"articleCount":143,"color":8,"createdAt":157,"id":158,"name":159,"slug":159,"updatedAt":157},"2026-04-17T19:35:19.300Z","019d9cf0-ca04-75bb-ad86-ce8da1c0be23","architecture",{"articleCount":134,"color":8,"createdAt":161,"id":162,"name":163,"slug":163,"updatedAt":161},"2026-04-23T12:00:11.615Z","019dba36-435e-765d-bfb2-c5be05362c27","astro",{"articleCount":134,"color":8,"createdAt":165,"id":166,"name":167,"slug":167,"updatedAt":165},"2026-06-01T20:00:15.958Z","019e84c5-cc55-7377-9e5d-77240ea8a880","authentication",{"articleCount":134,"color":8,"createdAt":169,"id":170,"name":171,"slug":171,"updatedAt":169},"2026-05-05T00:00:19.020Z","019df56f-824c-7031-9e34-2f47ad139eb6","automation",{"articleCount":134,"color":8,"createdAt":173,"id":174,"name":175,"slug":175,"updatedAt":173},"2026-06-11T16:00:12.019Z","019eb769-9af2-7471-b482-3f1a404f802e","azure",{"articleCount":177,"color":8,"createdAt":178,"id":179,"name":180,"slug":180,"updatedAt":178},2,"2026-04-17T20:27:50.776Z","019d9d20-e077-71cc-a605-8ac2a1566143","backend",{"articleCount":152,"color":8,"createdAt":182,"id":183,"name":184,"slug":184,"updatedAt":182},"2026-04-08T06:47:56.976Z","019d6bd9-010e-772d-b2f0-9378a042a676","best-practices",{"articleCount":134,"color":8,"createdAt":186,"id":187,"name":188,"slug":188,"updatedAt":186},"2026-06-06T00:00:11.711Z","019e9a3a-e5be-74b3-a01a-92c1f9427a2c","beta",{"articleCount":134,"color":8,"createdAt":190,"id":191,"name":192,"slug":192,"updatedAt":190},"2026-06-10T13:53:29.711Z","019eb1cf-3e6e-70f0-a761-0fb9b61d5675","budgeting",{"articleCount":129,"color":8,"createdAt":194,"id":195,"name":196,"slug":196,"updatedAt":194},"2026-06-16T16:11:31.438Z","019ed133-c4ee-70bb-8e21-7dc86e8adee4","bun",{"articleCount":134,"color":8,"createdAt":198,"id":199,"name":200,"slug":200,"updatedAt":198},"2026-05-19T20:00:14.559Z","019e41d3-1ade-77b0-9e4f-e9b97a6361ca","cdn",{"articleCount":129,"color":8,"createdAt":202,"id":203,"name":204,"slug":204,"updatedAt":202},"2026-06-27T16:00:12.237Z","019f09cf-5bcd-751c-8d46-9e123bd784af","clean-code",{"articleCount":129,"color":8,"createdAt":206,"id":207,"name":208,"slug":208,"updatedAt":206},"2026-05-16T18:48:40.777Z","019e321e-8248-75cc-9b69-59c2db6dd846","cli",{"articleCount":134,"color":8,"createdAt":210,"id":211,"name":212,"slug":212,"updatedAt":210},"2026-05-05T00:00:19.014Z","019df56f-8246-747f-be4b-a716863a93ea","cloud-platform",{"articleCount":129,"color":8,"createdAt":214,"id":215,"name":216,"slug":216,"updatedAt":214},"2026-06-16T16:11:31.289Z","019ed133-c458-74d8-a5c9-654f77837e7c","cloudflare",{"articleCount":129,"color":8,"createdAt":218,"id":219,"name":220,"slug":220,"updatedAt":218},"2026-07-27T18:11:45.304Z","019fa4c6-93c3-76ea-baa3-7d5fe541ac5b","cms",{"articleCount":129,"color":8,"createdAt":222,"id":223,"name":224,"slug":224,"updatedAt":222},"2026-04-30T04:19:02.045Z","019ddc9c-931c-743d-a1cb-e4449630fe47","collaboration",{"articleCount":129,"color":8,"createdAt":226,"id":227,"name":228,"slug":228,"updatedAt":226},"2026-06-10T13:53:29.567Z","019eb1cf-3dde-776d-9398-4863764f9ac3","community",{"articleCount":129,"color":8,"createdAt":230,"id":231,"name":232,"slug":232,"updatedAt":230},"2026-05-06T16:00:17.128Z","019dfe04-bee8-7384-bc58-a712f677807c","comparison",{"articleCount":129,"color":8,"createdAt":234,"id":235,"name":236,"slug":236,"updatedAt":234},"2026-05-14T12:00:21.354Z","019e265b-f569-71d8-a02a-a17ec8180644","component-design",{"articleCount":129,"color":8,"createdAt":238,"id":239,"name":240,"slug":240,"updatedAt":238},"2026-07-18T20:00:18.730Z","019f76d0-bb29-72d6-8d0b-05ffd1d3c8ed","composables",{"articleCount":152,"color":8,"createdAt":242,"id":243,"name":244,"slug":244,"updatedAt":242},"2026-04-08T06:47:42.915Z","019d6bd8-ca21-71c5-a236-37d94fe57d24","composition-api",{"articleCount":129,"color":8,"createdAt":246,"id":247,"name":248,"slug":248,"updatedAt":246},"2026-06-27T12:00:13.113Z","019f08f3-a538-74ed-82c5-038edce7100a","copilot",{"articleCount":134,"color":8,"createdAt":250,"id":251,"name":252,"slug":252,"updatedAt":250},"2026-04-25T12:00:12.674Z","019dc482-ff81-73ac-9b1c-6ad47f0afde0","data-management",{"articleCount":134,"color":8,"createdAt":254,"id":255,"name":256,"slug":256,"updatedAt":254},"2026-06-04T20:00:17.367Z","019e9438-e5d7-731f-bf47-8dcd86c6655c","data-privacy",{"articleCount":129,"color":8,"createdAt":258,"id":259,"name":260,"slug":260,"updatedAt":258},"2026-05-05T12:00:17.083Z","019df802-a8bb-775a-b843-93d883c7dfc5","data-science",{"articleCount":134,"color":8,"createdAt":262,"id":263,"name":264,"slug":264,"updatedAt":262},"2026-06-11T16:00:12.028Z","019eb769-9afb-7709-8a67-2a12f5e557c7","deepseek",{"articleCount":129,"color":8,"createdAt":266,"id":267,"name":268,"slug":268,"updatedAt":266},"2026-05-25T08:00:12.834Z","019e5e26-0e21-7366-87c7-0b1334180b0a","dependency-cruiser",{"articleCount":129,"color":8,"createdAt":270,"id":271,"name":272,"slug":272,"updatedAt":270},"2026-04-18T04:30:00.710Z","019d9eda-5005-7329-a463-189572e25635","deployment",{"articleCount":177,"color":8,"createdAt":274,"id":275,"name":276,"slug":276,"updatedAt":274},"2026-04-21T12:00:11.373Z","019dafe9-8a6d-7218-81f1-37052cbe9b78","development",{"articleCount":129,"color":8,"createdAt":278,"id":279,"name":280,"slug":280,"updatedAt":278},"2026-06-29T08:00:12.101Z","019f1264-9f44-762d-b5fd-837839fdc586","devtools",{"articleCount":134,"color":8,"createdAt":282,"id":283,"name":284,"slug":284,"updatedAt":282},"2026-05-29T20:00:13.197Z","019e7552-ad8c-731f-ad8b-49253ed0e1b9","docker",{"articleCount":129,"color":8,"createdAt":286,"id":287,"name":288,"slug":288,"updatedAt":286},"2026-06-27T12:00:13.081Z","019f08f3-a518-7607-aa8c-782b4f10c2ed","documentation",{"articleCount":129,"color":8,"createdAt":290,"id":291,"name":292,"slug":292,"updatedAt":290},"2026-04-30T04:19:02.055Z","019ddc9c-9327-744f-a2da-31b64c7b6ba4","editor",{"articleCount":129,"color":8,"createdAt":294,"id":295,"name":296,"slug":296,"updatedAt":294},"2026-07-06T12:00:24.261Z","019f374d-0cc4-71ff-b906-ebaec8b0c343","eslint",{"articleCount":134,"color":8,"createdAt":298,"id":299,"name":300,"slug":300,"updatedAt":298},"2026-05-02T00:00:23.123Z","019de5fc-7e52-740a-807c-d322c373865b","firewall",{"articleCount":129,"color":8,"createdAt":302,"id":303,"name":304,"slug":304,"updatedAt":302},"2026-05-06T16:00:17.134Z","019dfe04-beee-7481-b8e7-4034640e840a","frameworks",{"articleCount":134,"color":8,"createdAt":306,"id":307,"name":308,"slug":308,"updatedAt":306},"2026-04-08T06:47:56.883Z","019d6bd9-00b2-7199-8e88-2530ef258032","generics",{"articleCount":129,"color":8,"createdAt":310,"id":311,"name":312,"slug":312,"updatedAt":310},"2026-07-27T18:11:45.390Z","019fa4c6-9419-7657-844e-58ec868ed664","git",{"articleCount":177,"color":8,"createdAt":314,"id":315,"name":316,"slug":316,"updatedAt":314},"2026-07-15T00:00:22.207Z","019f6313-12bf-7151-81f2-c8b43b09d979","html",{"articleCount":134,"color":8,"createdAt":318,"id":319,"name":320,"slug":320,"updatedAt":318},"2026-05-06T00:00:17.012Z","019dfa95-d673-71ef-be4a-8761512ffe5c","infrastructure",{"articleCount":129,"color":8,"createdAt":322,"id":323,"name":324,"slug":324,"updatedAt":322},"2026-06-16T16:11:31.264Z","019ed133-c43f-704f-8c1a-fbc299c8a3e5","javascript",{"articleCount":129,"color":8,"createdAt":326,"id":327,"name":328,"slug":328,"updatedAt":326},"2026-07-13T08:00:18.266Z","019f5a7d-bf5a-76e0-903a-c87435cc3e09","lazy-loading",{"articleCount":129,"color":8,"createdAt":330,"id":331,"name":332,"slug":332,"updatedAt":330},"2026-05-11T12:00:19.963Z","019e16e8-dbfa-76d6-bb2d-793aee049186","loading",{"articleCount":134,"color":8,"createdAt":334,"id":335,"name":336,"slug":336,"updatedAt":334},"2026-04-25T12:00:12.682Z","019dc482-ff8a-7698-8af5-95db54a26d6b","local-first",{"articleCount":129,"color":8,"createdAt":338,"id":339,"name":340,"slug":340,"updatedAt":338},"2026-05-14T12:00:21.370Z","019e265b-f579-71cd-84b2-ac385b5225ae","maintainability",{"articleCount":129,"color":8,"createdAt":342,"id":343,"name":344,"slug":344,"updatedAt":342},"2026-05-10T16:00:18.613Z","019e129e-34b4-7107-acfb-27f6b8604eb0","management",{"articleCount":129,"color":8,"createdAt":346,"id":347,"name":348,"slug":348,"updatedAt":346},"2026-06-27T12:00:13.065Z","019f08f3-a508-7334-aa03-12b281698ea8","markdown",{"articleCount":129,"color":8,"createdAt":350,"id":351,"name":352,"slug":352,"updatedAt":350},"2026-07-28T12:00:27.878Z","019fa899-02e6-758e-bdcb-8a4a923507df","mcp",{"articleCount":129,"color":8,"createdAt":354,"id":355,"name":356,"slug":356,"updatedAt":354},"2026-06-17T12:00:12.439Z","019ed574-0a96-7485-9c90-522e4be3e092","meta-tags",{"articleCount":134,"color":8,"createdAt":358,"id":359,"name":360,"slug":360,"updatedAt":358},"2026-05-26T08:00:14.598Z","019e634c-7105-7073-bc86-c32fa0a4401b","microfrontends",{"articleCount":134,"color":8,"createdAt":362,"id":363,"name":364,"slug":364,"updatedAt":362},"2026-05-19T16:00:13.516Z","019e40f7-5ccc-729c-92ba-bcc0aad8a16f","microvm",{"articleCount":134,"color":8,"createdAt":366,"id":367,"name":368,"slug":368,"updatedAt":366},"2026-05-05T00:00:19.025Z","019df56f-8250-768c-a659-b9f524ff902c","multi-tenant",{"articleCount":134,"color":8,"createdAt":370,"id":371,"name":372,"slug":372,"updatedAt":370},"2026-05-08T04:00:17.998Z","019e05be-4c4d-759e-a51e-8ac760f82f6d","nextjs",{"articleCount":129,"color":8,"createdAt":374,"id":375,"name":376,"slug":376,"updatedAt":374},"2026-04-17T19:35:19.293Z","019d9cf0-c9fc-76a0-8c4e-b818a89c3774","nitro",{"articleCount":378,"color":8,"createdAt":379,"id":81,"name":82,"slug":82,"updatedAt":379},27,"2026-04-08T06:47:55.381Z",{"articleCount":129,"color":8,"createdAt":381,"id":382,"name":383,"slug":383,"updatedAt":381},"2026-04-30T04:19:02.038Z","019ddc9c-9315-735e-a7e8-8424790e8859","nuxt-ui",{"articleCount":129,"color":8,"createdAt":385,"id":386,"name":387,"slug":387,"updatedAt":385},"2026-06-08T12:00:16.030Z","019ea71a-dc9d-7607-9cfa-df0f31ab5876","observability",{"articleCount":134,"color":8,"createdAt":389,"id":390,"name":391,"slug":391,"updatedAt":389},"2026-05-04T20:00:20.503Z","019df493-ce17-76ed-bd80-2a3914e0f409","open-source",{"articleCount":129,"color":8,"createdAt":393,"id":394,"name":395,"slug":395,"updatedAt":393},"2026-06-08T12:00:16.022Z","019ea71a-dc95-72b8-a7e3-70f9e2ac3710","opentelemetry",{"articleCount":152,"color":8,"createdAt":397,"id":398,"name":399,"slug":399,"updatedAt":397},"2026-05-18T12:00:14.389Z","019e3af5-4a35-705c-8ab1-4404b653e0e8","optimization",{"articleCount":129,"color":8,"createdAt":401,"id":402,"name":403,"slug":403,"updatedAt":401},"2026-05-28T20:00:13.016Z","019e702c-50d7-74eb-8849-8b1cebcf411e","orchestration",{"articleCount":405,"color":8,"createdAt":406,"id":126,"name":127,"slug":127,"updatedAt":406},16,"2026-04-08T06:47:42.920Z",{"articleCount":129,"color":8,"createdAt":408,"id":409,"name":410,"slug":410,"updatedAt":408},"2026-06-10T13:53:29.575Z","019eb1cf-3de7-7326-87d9-c55ad1c0fa39","personalization",{"articleCount":129,"color":8,"createdAt":412,"id":105,"name":106,"slug":106,"updatedAt":412},"2026-04-17T19:35:19.263Z",{"articleCount":134,"color":8,"createdAt":414,"id":415,"name":416,"slug":416,"updatedAt":414},"2026-05-02T00:00:23.112Z","019de5fc-7e47-7075-8aeb-9e90f7689f57","postgres",{"articleCount":134,"color":8,"createdAt":418,"id":419,"name":420,"slug":420,"updatedAt":418},"2026-05-19T20:00:14.575Z","019e41d3-1aee-70c8-a07c-cec870115d14","pricing",{"articleCount":129,"color":8,"createdAt":422,"id":423,"name":424,"slug":424,"updatedAt":422},"2026-05-10T16:00:18.603Z","019e129e-34aa-723b-a568-45737915c7bf","qa",{"articleCount":129,"color":8,"createdAt":426,"id":427,"name":428,"slug":428,"updatedAt":426},"2026-05-08T04:00:18.013Z","019e05be-4c5c-75ad-8df5-602b3db57983","react",{"articleCount":152,"color":8,"createdAt":430,"id":59,"name":60,"slug":60,"updatedAt":430},"2026-04-20T12:00:11.653Z",{"articleCount":152,"color":8,"createdAt":432,"id":433,"name":434,"slug":434,"updatedAt":432},"2026-04-17T20:27:50.585Z","019d9d20-dfb9-7041-9973-39c545b33a2d","release",{"articleCount":134,"color":8,"createdAt":436,"id":437,"name":438,"slug":438,"updatedAt":436},"2026-05-26T08:00:14.619Z","019e634c-711a-728f-9b63-20f2c8b37ccb","routing",{"articleCount":134,"color":8,"createdAt":440,"id":441,"name":442,"slug":442,"updatedAt":440},"2026-05-19T16:00:13.509Z","019e40f7-5cc4-72e1-8f8b-692dd29fc716","sandbox",{"articleCount":129,"color":8,"createdAt":444,"id":445,"name":446,"slug":446,"updatedAt":444},"2026-05-14T12:00:21.362Z","019e265b-f571-7677-a537-2f7e96a490bf","scalability",{"articleCount":134,"color":8,"createdAt":448,"id":449,"name":450,"slug":450,"updatedAt":448},"2026-05-04T20:00:20.521Z","019df493-ce28-75e9-93d5-13251407a27b","scanning",{"articleCount":152,"color":8,"createdAt":452,"id":453,"name":454,"slug":454,"updatedAt":452},"2026-04-27T08:00:12.420Z","019dcdf3-fc84-73aa-a0be-6b7196c5a2e9","security",{"articleCount":129,"color":8,"createdAt":456,"id":457,"name":458,"slug":458,"updatedAt":456},"2026-06-17T12:00:12.428Z","019ed574-0a8b-7566-976f-8c281c820ed0","seo",{"articleCount":129,"color":8,"createdAt":460,"id":461,"name":462,"slug":462,"updatedAt":460},"2026-06-17T12:00:12.433Z","019ed574-0a91-74d8-b806-56681bb4b477","sitemap",{"articleCount":129,"color":8,"createdAt":464,"id":465,"name":466,"slug":466,"updatedAt":464},"2026-07-18T16:00:27.576Z","019f75f5-23b8-72eb-a2bf-79dd1fed3863","software-development",{"articleCount":129,"color":8,"createdAt":468,"id":469,"name":470,"slug":470,"updatedAt":468},"2026-04-17T19:35:19.297Z","019d9cf0-ca00-749d-9101-1c63bf62e215","spas",{"articleCount":177,"color":8,"createdAt":472,"id":473,"name":474,"slug":474,"updatedAt":472},"2026-06-03T16:00:12.620Z","019e8e36-bd4b-740d-b23a-81858b24025b","ssg",{"articleCount":476,"color":8,"createdAt":477,"id":478,"name":479,"slug":479,"updatedAt":477},9,"2026-04-08T06:47:43.020Z","019d6bd8-ca89-735e-a52a-ee53a80a77a9","ssr",{"articleCount":134,"color":8,"createdAt":481,"id":482,"name":483,"slug":483,"updatedAt":481},"2026-04-30T04:19:02.613Z","019ddc9c-9555-7544-a3e3-0605d2c1ea82","startup",{"articleCount":152,"color":8,"createdAt":485,"id":486,"name":487,"slug":487,"updatedAt":485},"2026-04-18T12:00:12.027Z","019da076-78fb-706b-9a4c-cee0c989cfff","state-management",{"articleCount":134,"color":8,"createdAt":489,"id":490,"name":491,"slug":491,"updatedAt":489},"2026-06-06T00:00:11.717Z","019e9a3a-e5c5-76d3-86e4-576c151a87b3","storage",{"articleCount":129,"color":8,"createdAt":493,"id":494,"name":495,"slug":495,"updatedAt":493},"2026-06-17T12:00:12.446Z","019ed574-0a9e-7712-8bc5-a0102787fe48","structured-data",{"articleCount":129,"color":8,"createdAt":497,"id":498,"name":499,"slug":499,"updatedAt":497},"2026-05-10T16:00:18.597Z","019e129e-34a4-771a-844d-09a7edefcd64","tdd",{"articleCount":134,"color":8,"createdAt":501,"id":502,"name":503,"slug":503,"updatedAt":501},"2026-06-04T20:00:17.351Z","019e9438-e5c6-7681-8704-897c7b499eb4","terms-of-service",{"articleCount":177,"color":8,"createdAt":505,"id":506,"name":507,"slug":507,"updatedAt":505},"2026-04-09T06:11:45.799Z","019d70de-3c07-76bf-9688-9619e1b0d427","testing",{"articleCount":129,"color":8,"createdAt":509,"id":34,"name":35,"slug":35,"updatedAt":509},"2026-06-16T16:11:31.088Z",{"articleCount":134,"color":8,"createdAt":511,"id":512,"name":513,"slug":513,"updatedAt":511},"2026-05-02T00:00:23.130Z","019de5fc-7e59-7426-8d46-e79e4bcf0d56","tls",{"articleCount":515,"color":8,"createdAt":516,"id":63,"name":64,"slug":64,"updatedAt":516},10,"2026-04-08T06:47:55.591Z",{"articleCount":152,"color":8,"createdAt":518,"id":519,"name":520,"slug":520,"updatedAt":518},"2026-04-08T06:47:56.778Z","019d6bd9-0049-72ba-8cfa-139b1c1b249d","typescript",{"articleCount":7,"color":8,"createdAt":477,"id":9,"name":10,"slug":10,"updatedAt":477},{"articleCount":129,"color":8,"createdAt":523,"id":524,"name":525,"slug":525,"updatedAt":523},"2026-05-11T12:00:19.969Z","019e16e8-dc00-714d-911a-a5bf39238587","user-experience",{"articleCount":129,"color":8,"createdAt":527,"id":528,"name":529,"slug":529,"updatedAt":527},"2026-05-18T12:00:14.379Z","019e3af5-4a29-759a-81b0-b6d502b2449e","v-memo",{"articleCount":134,"color":8,"createdAt":531,"id":532,"name":533,"slug":533,"updatedAt":531},"2026-04-30T04:19:02.228Z","019ddc9c-93d3-763e-ad3c-d3ad78642de7","vercel",{"articleCount":129,"color":8,"createdAt":535,"id":536,"name":537,"slug":537,"updatedAt":535},"2026-07-13T08:00:18.274Z","019f5a7d-bf61-746b-a44b-5c0a16ff57d3","video",{"articleCount":152,"color":8,"createdAt":539,"id":540,"name":541,"slug":541,"updatedAt":539},"2026-04-17T19:35:19.289Z","019d9cf0-c9f8-7411-beed-02265d8271db","vite",{"articleCount":129,"color":8,"createdAt":543,"id":544,"name":545,"slug":545,"updatedAt":543},"2026-04-25T18:08:02.132Z","019dc5d3-c054-70e2-bca4-08e2a2b9a096","vitest",{"articleCount":129,"color":8,"createdAt":547,"id":548,"name":549,"slug":549,"updatedAt":547},"2026-06-27T12:00:13.107Z","019f08f3-a532-7049-a02c-c17a4fd99306","vscode",{"articleCount":551,"color":8,"createdAt":552,"id":31,"name":32,"slug":32,"updatedAt":552},32,"2026-04-08T06:47:42.793Z",{"articleCount":129,"color":8,"createdAt":554,"id":555,"name":556,"slug":556,"updatedAt":554},"2026-04-18T12:00:12.007Z","019da076-78e6-76bd-b0d4-4e0597d36378","vue-router",{"articleCount":134,"color":8,"createdAt":558,"id":559,"name":560,"slug":560,"updatedAt":558},"2026-05-04T20:00:20.510Z","019df493-ce1d-7039-811a-ed57bf081d26","vulnerability",{"articleCount":562,"color":8,"createdAt":563,"id":564,"name":565,"slug":565,"updatedAt":563},3,"2026-05-05T12:00:17.078Z","019df802-a8b6-74d2-a0cd-b0509cf502fa","web-development",{"articleCount":562,"color":8,"createdAt":567,"id":568,"name":569,"slug":569,"updatedAt":567},"2026-05-10T16:00:18.576Z","019e129e-3490-7739-a218-5454a8c15d6e","workflow"]