<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Vue PDF Viewer Blog]]></title><description><![CDATA[Vue PDF Viewer is a powerful PDF Viewer library for Vue.js or Nuxt. This blog offers tutorials and articles to help developers embed PDF Viewer in their apps.]]></description><link>https://blog.vue-pdf-viewer.dev</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1728283589379/ddfec402-9769-469c-b70a-93b956b108f2.png</url><title>Vue PDF Viewer Blog</title><link>https://blog.vue-pdf-viewer.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Mon, 20 Apr 2026 12:55:47 GMT</lastBuildDate><atom:link href="https://blog.vue-pdf-viewer.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[🔥 Best Vue.js UI Libraries for 2026: Top 5 Picks (+ Bonus) 🚀]]></title><description><![CDATA[Edit: Back in 2025, I shared a list of the "🌟 Vue 3 UI Libraries: 6 Most Popular Picks for 2025 🚀". Now in 2026, I'm revisiting this topic to see what's changed and which libraries are still making waves 🎉
Vue.js is still one of the top frameworks...]]></description><link>https://blog.vue-pdf-viewer.dev/best-vuejs-ui-libraries-for-2026-top-5-picks-bonus</link><guid isPermaLink="true">https://blog.vue-pdf-viewer.dev/best-vuejs-ui-libraries-for-2026-top-5-picks-bonus</guid><category><![CDATA[Vue.js]]></category><category><![CDATA[Nuxt]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[TypeScript]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[Frontend Development]]></category><dc:creator><![CDATA[Anson Chieng]]></dc:creator><pubDate>Tue, 20 Jan 2026 10:48:58 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1768905665605/eb11952b-be21-40c3-9d41-abc4ecfd5af6.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>Edit: Back in 2025, I shared a list of the "</em><a target="_blank" href="https://blog.vue-pdf-viewer.dev/vue-3-ui-libraries-6-most-popular-picks-for-2025"><em>🌟 Vue 3 UI Libraries: 6 Most Popular Picks for 2025 🚀</em></a><em>". Now in 2026, I'm revisiting this topic to see what's changed and which libraries are still making waves 🎉</em></p>
<p>Vue.js is still one of the top frameworks you can use to build modern web apps. A good UI library helps make working with Vue.js even better. Every year, the landscape shifts a bit, some libraries rise, others fade, and new players enter the game.</p>
<p>In 2025, we saw Radix Vue rebrand to Reka UI. NuxtLabs joined Vercel and made Nuxt UI Pro features free and open-source. Headless libraries got even more popular. More people now focus on accessibility and on using Tailwind CSS together.</p>
<p>In this article, I will talk about 5 top Vue.js UI libraries for web development in 2026. These are the ones you should know about, whether you want to start a new project or make your old one better. Let’s jump in! 🚀</p>
<p><img src="https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExNnpoaDEwaG15MGsyNXQ5ZHRmZXVxOWFiN3dhdXBkdzV5cjlhZ3g2aSZlcD12MV9naWZzX3NlYXJjaCZjdD1n/RrVzUOXldFe8M/giphy.gif" alt="Gif let's go" class="image--center mx-auto" /></p>
<hr />
<h2 id="heading-vue-pdf-viewer-flexible-and-powerful-vuejs-pdf-component">Vue PDF Viewer: Flexible and Powerful Vue.js PDF Component</h2>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/banx6w81hbmn1ffyv8d2.png" alt="Vue PDF Viewer" class="image--center mx-auto" /></p>
<p>Just a quick background about what I’m working on. <a target="_blank" href="https://www.vue-pdf-viewer.dev/?utm_source=blog&amp;utm_medium=referral&amp;utm_content=best-vuejs-ui-libraries-for-2026-top-5-picks-bonus">Vue PDF Viewer</a> renders the PDF viewer on your Vue or Nuxt websites so that your users can interact with your PDF document without leaving your sites. The component has over 20 features including theme and toolbar customization, annotation, web responsive and more.</p>
<p>I’d love for you to check Vue PDF Viewer out! Your support means the world and helps me create more awesome content like this. ❤️</p>
<hr />
<h3 id="heading-1-vuetify">1. Vuetify</h3>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pci6rm6cle9kwhn60dlk.png" alt="Vuetify" /></p>
<p>Vuetify is still one of the top Vue component library for using Material Design with Vue.js. It's been around for years, and that maturity shows. The documentation is excellent, the component library is massive, and the community support is strong.</p>
<p>What makes Vuetify stand out is its balance of power and being easy to change. You get 80+ ready-made components out of the box, But when you want to change how things look, it is simple and easy to do so. Vuetify works well with Nuxt 3. It also lets you set up SSR or SPA, so you have more ways to build your site.</p>
<p>As of January 2026, Vuetify has over <strong>41,000 GitHub stars</strong> and around <strong>700,000 weekly downloads</strong>. This shows the steady growth and the trust people have in it.</p>
<p><strong>Features:</strong></p>
<ul>
<li><p>80+ pre-designed Material Design components</p>
</li>
<li><p>Powerful theming with easy customization</p>
</li>
<li><p>SSR and SPA support with excellent Nuxt 3 integration</p>
</li>
</ul>
<p>Learn more on <a target="_blank" href="https://vuetifyjs.com">https://vuetifyjs.com</a></p>
<hr />
<h3 id="heading-2-primevue">2. PrimeVue</h3>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rv9epqh32int9qtnrmvk.png" alt="PrimeVue" /></p>
<p>PrimeVue continues to show good results. Backed by PrimeTek, this library gives you more than 90 components, including various Vue components and over 200 icons. It stands out as one of the best options in the Vue ecosystem. It's lightweight, has solid Tailwind CSS integration, and handles enterprise-level complexity without feeling bloated.</p>
<p>The API is easy to use, so customization doesn't require jumping through hoops. You can get data tables, charts, or parts for forms with PrimeVue. It has all that you need.</p>
<p>As of January 2026, PrimeVue has over <strong>14,000 GitHub stars</strong> (up from 11,000 in 2025) and around <strong>480,000 weekly downloads</strong>. The growth has been impressive.</p>
<p><strong>Features:</strong></p>
<ul>
<li><p>There are over 90 components. These include charts, data tables, and parts you use in forms.</p>
</li>
<li><p>WAI-ARIA compliant accessibility</p>
</li>
<li><p>Tailwind CSS integration and flexible theming</p>
</li>
</ul>
<p>Learn more on <a target="_blank" href="https://primevue.org/">https://primevue.org/</a></p>
<hr />
<h3 id="heading-3-element-plus">3. Element Plus</h3>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7c3b99qmxgsheyw8vkab.png" alt="Element Plus" /></p>
<p>Element Plus picked up where Element UI left off, and now it is one of the great choices for Vue 3. The clean UI style, strong TypeScript support, and Composition API design make it a good pick for any project size.</p>
<p>What stands out is how easy it is to get started. The documentation is thorough, the examples are practical, and the component library covers most use cases without much customization needed. Internationalization support is built in, which is a bonus for global projects.</p>
<p>As of January 2026, Element Plus has over <strong>27,000 GitHub stars</strong> and around <strong>350,000 weekly downloads</strong>. Steady and reliable.</p>
<p><strong>Features</strong>:</p>
<ul>
<li><p>Rich component library with clean, customizable themes</p>
</li>
<li><p>Strong TypeScript and Composition API support</p>
</li>
<li><p>Built-in internationalization (i18n)</p>
</li>
</ul>
<p>Learn more on <a target="_blank" href="https://element-plus.org/en-US/">https://element-plus.org/en-US/</a></p>
<hr />
<h3 id="heading-4-quasar">4. Quasar</h3>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6as9kswv493qb6c2vudc.png" alt="Quasar" /></p>
<p>Quasar is more than a UI library. It's a full framework that lets you build SPAs, SSR apps, PWAs, mobile apps, and desktop apps from a single codebase. This cross-platform use is what makes Quasar stand out from others.</p>
<p>On the UI side, you get 70+ Material Design components, several sets of icons (Material, FontAwesome, Bootstrap, and more), and tools built-in for things like animations, dates, and using different languages. The documentation is clear and well-organized. This makes it easier for you when you work on many platforms.</p>
<p>As of January 2026, Quasar has over <strong>27,000 GitHub stars</strong> and around <strong>190,000 weekly downloads</strong>. It's a mature project that continues to deliver.</p>
<p><strong>Features:</strong></p>
<ul>
<li><p>Cross-platform: SPA, SSR, PWA, Mobile (Cordova/Capacitor), Desktop (Electron)</p>
</li>
<li><p>70+ Material Design components with multiple icon sets</p>
</li>
<li><p>Built-in i18n, animations, and utility functions</p>
</li>
</ul>
<p>Learn more on <a target="_blank" href="https://quasar.dev/">https://quasar.dev/</a></p>
<hr />
<h3 id="heading-5-reka-ui-formerly-radix-vue">5. Reka UI (formerly Radix Vue)</h3>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e3lvvg6w68opah8cdzpq.png" alt="Reka UI" /></p>
<p>Radix Vue rebranded to Reka UI in 2025, but the main goal remains the same. It gives you headless, accessible components for Vue. If you know Radix UI in React, this is the same thing but for Vue.</p>
<p>Reka UI gives you unstyled building blocks like dialogs, dropdowns, sliders, and tabs. You add the style you want, and it handles the accessibility and behavior. Every component is WAI-ARIA compliant out of the box, with proper keyboard navigation and focus management all set up.</p>
<p>The library has seen a lot of people use it. As of January 2026, Reka UI has around <strong>6,100 GitHub stars</strong> and over <strong>590,000 weekly downloads</strong>. A big part of this growth comes from Nuxt UI, which uses Reka UI as its base.</p>
<p><strong>Features:</strong></p>
<ul>
<li><p>Headless, unstyled components that give you full control over how you style them</p>
</li>
<li><p>WAI-ARIA compliant with keyboard navigation and focus management</p>
</li>
<li><p>Lightweight and modular for Vue 3 and Nuxt projects</p>
</li>
</ul>
<p>Learn more on <a target="_blank" href="https://www.radix-vue.com/">https://www.radix-vue.com/</a></p>
<hr />
<h3 id="heading-special-mention-nuxt-ui">Special Mention: Nuxt UI</h3>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ade4fooe06rqg935mx7b.png" alt="Nuxt UI" /></p>
<p>Nuxt UI had a big year. In 2025, NuxtLabs became a part of Vercel and merged Nuxt UI Pro into the free tier. Now, you get over 100 components, top templates, and a full Figma kit. All of this is free for everyone.</p>
<p>Nuxt UI is made for Nuxt projects. It uses Reka UI and Tailwind CSS as its base. It also supports plain Vue with a Vite plugin. SSR, SSG, and dark mode work out of the box. If you're in the Nuxt ecosystem, this is the obvious choice.</p>
<p>As of January 2026, Nuxt UI has around <strong>6,100 GitHub stars</strong> and over <strong>169,000 weekly downloads</strong>. With the v4 release, these numbers will likely go up.</p>
<p><strong>Features:</strong></p>
<ul>
<li><p>Over 100 components, now fully open source (previously Pro)</p>
</li>
<li><p>Built on Reka UI and Tailwind CSS</p>
</li>
<li><p>Works with Nuxt and plain Vue (via Vite plugin)</p>
</li>
</ul>
<p>Learn more on <a target="_blank" href="https://ui.nuxt.com/">https://ui.nuxt.com/</a></p>
<hr />
<h2 id="heading-conclusion">Conclusion</h2>
<p>So which Vue.js UI library should you use for your next project? Here's the quick run-through:</p>
<ul>
<li><p>Go with <strong>Vuetify</strong> if you want a strong and well-known library that uses Material Design. It has tons of components and strong community support.</p>
</li>
<li><p>Choose <strong>PrimeVue</strong> for a full library that is enterprise-ready and has great Tailwind CSS support.</p>
</li>
<li><p>Pick <strong>Element Plus</strong> when you need a clean and reliable library. It works well with TypeScript and easy internalization.</p>
</li>
<li><p>Use <strong>Quasar</strong> if you want to build apps for multiple platforms (SPA, PWA, mobile, desktop) from a single codebase.</p>
</li>
<li><p>Try <strong>Reka UI</strong> when you want headless, accessible building blocks and full control over styling.</p>
</li>
</ul>
<p>Bonus: Nuxt UI is now fully open source with 100+ components. If you're in the Nuxt ecosystem, it's definitelly a top choice.</p>
<p>Each library has its own strengths. The right choice for you will depends on your project's needs, your team's workflow, and how much styling control you want. Try different ones, see what works, and build something great. 🚀</p>
<hr />
<h1 id="heading-vue-pdf-viewer-a-pdf-viewer-made-for-vuejs-developers">Vue PDF Viewer: A PDF Viewer Made for Vue.js Developers 🚀</h1>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/banx6w81hbmn1ffyv8d2.png" alt="Vue PDF Viewer" /></p>
<p>I mentioned <a target="_blank" href="https://www.vue-pdf-viewer.dev/?utm_source=blog&amp;utm_medium=referral&amp;utm_content=best-vuejs-ui-libraries-for-2026-top-5-picks-bonus">Vue PDF Viewer</a> earlier, and I'd love for you to check it out. We built it to make PDF viewing in Vue and Nuxt effortless, with theme customization, annotation support, responsive layouts, localization, and smooth integration built in. You do not need a long setup. Just add it, and it will work.</p>
<p>If you need to use PDF tools in your project, give it a try! Your support lets us make the library better and share more helpful content for the Vue community. 🙏</p>
<p>Thanks for reading, and good luck with your next project!</p>
<p><img src="https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExYW9haTZzcGt0eHZ0YmcyYWdxNTFqZzBiMDh6enUyOHd4NTRxc3RjayZlcD12MV9naWZzX3NlYXJjaCZjdD1n/3UkqVq3F50bVCi9URl/giphy.gif" alt="Cat dancing GIF" class="image--center mx-auto" /></p>
]]></content:encoded></item><item><title><![CDATA[🚀 6 Open-Source PDF Viewer and Annotation libraries every Vue developers should know [2025] ✨]]></title><description><![CDATA[PDF Viewer and annotation features have become standard in modern web apps. Whether you're building dashboards, admin panels, or document platforms, users expect smooth PDF reading experience and the ability to mark up files with comments, highlights...]]></description><link>https://blog.vue-pdf-viewer.dev/6-open-source-pdf-viewer-and-annotation-libraries-every-vue-developers-should-know-2025</link><guid isPermaLink="true">https://blog.vue-pdf-viewer.dev/6-open-source-pdf-viewer-and-annotation-libraries-every-vue-developers-should-know-2025</guid><category><![CDATA[Vue.js]]></category><category><![CDATA[Nuxt]]></category><category><![CDATA[TypeScript]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[Frontend Development]]></category><category><![CDATA[pdfjs-dist]]></category><dc:creator><![CDATA[Anson Chieng]]></dc:creator><pubDate>Mon, 01 Sep 2025 16:00:34 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1756741702837/622edba2-1e1b-4f83-938c-032914871d57.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>PDF Viewer and annotation features have become standard in modern web apps. Whether you're building dashboards, admin panels, or document platforms, users expect smooth PDF reading experience and the ability to mark up files with comments, highlights, or signature, all without ever leaving your site.</p>
<p>For Vue developers, knowing which open-source PDF Viewer and annotation libraries work best can save hours of trial and error. You can even mix and match libraries to tackle multiple use cases, from fast document rendering to advanced markup. The right solution solve the hassle of juggling pop-ups, downloads, or iframe workarounds.</p>
<p>Here're are the six open-source libraries you need to know as you look for the ideal fit for your next Vue.js project.</p>
<p><img src="https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExd2lrejZqdnEzdXp3cHdjbWkydjgwY2E0MGxxbGJ1eTFxcWw1bWliMCZlcD12MV9naWZzX3NlYXJjaCZjdD1n/LoCDk7fecj2dwCtSB3/giphy.gif" alt="Gif on bring it on" class="image--center mx-auto" /></p>
<hr />
<p>Before we jump into the list of libraries, here’s something worth checking out: a flexible <a target="_blank" href="https://www.vue-pdf-viewer.dev/?utm_source=blog&amp;utm_medium=referral&amp;utm_content=6-open-source-pdf-viewer-and-annotation-libraries-every-vue-developers-should-know">Vue PDF</a> rendering solution built specifically for Vue 3.</p>
<p>Whether you’re building a dashboard, AI PDF chat tool, or internal tool, Vue PDF Viewer makes it easy to embed PDF viewing right inside your app. It supports:</p>
<ul>
<li><p>Mobile responsive viewing</p>
</li>
<li><p>Built-in toolbar and search</p>
</li>
<li><p>Text selection, zoom, thumbnails, and more</p>
</li>
<li><p>Easy theming and layout overrides</p>
</li>
</ul>
<p>With minimal setup and strong TypeScript support, it’s a solid option if you’re looking for an all-in-one PDF solution with modern features and clean design.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ghuuzlxeymc3vh66cmzr.png" alt="Screenshot of Vue PDF Viewer" class="image--center mx-auto" /></p>
<hr />
<h2 id="heading-why-open-source-pdf-viewer-and-annotation-libraries-matter-for-vue-developers">Why Open-Source PDF Viewer and Annotation Libraries Matter for Vue Developers</h2>
<p>Building robust document features in Vue has moved way beyond just dropping a PDF link on a page. Users want to read, highlight, mark up, and sign documents right inside your app. Open-source PDF viewer and annotation libraries make this level of integration possible.</p>
<ul>
<li><p><strong>Cost Saving:</strong> No hidden usage or licensing fee. No vendor lock-in.</p>
</li>
<li><p><strong>Transparency:</strong> You can inspect, debug, and improve the code, with full visibility into how things work.</p>
</li>
<li><p><strong>Flexibility and Control:</strong> Customize, extend, or combine libraries to fit your app’s needs without being boxed in.</p>
</li>
</ul>
<hr />
<h2 id="heading-vue-focused-pdf-viewer-libraries">Vue-Focused PDF Viewer Libraries</h2>
<p>Before diving into specific libraries, it’s important to understand PDF.js. Most open-source PDF Viewer libraries for Vue are built on top of it. It's the backbone for rendering, navigating, and interacting with PDF files inside your browser.</p>
<h3 id="heading-what-is-mozilla-pdfjs">What is Mozilla PDF.js?</h3>
<p>PDF.js is an open-source JavaScript library built and maintained by Mozilla that allows you to render and interact with PDF files directly in modern web browsers. It relies on standard web technologies, making it highly compatible and easy to integrate into frontend stacks like Vue.</p>
<p>This tool isn’t just for displaying PDF pages. It gives you the control to create a full PDF Viewer with built-in zoom, search and text selection. For Vue developers, that means you can keep users in your app and offer rich document features, instead of handing them off to third-party tools.</p>
<p><strong>Key Features</strong></p>
<ul>
<li><p>Render large files with search, zoom, and page navigation</p>
</li>
<li><p>No license restrictions and vendor lock-in. Use, modify, and ship updates as you see fit</p>
</li>
<li><p>Responsive viewing for most modern browsers</p>
</li>
<li><p>Easily integrate with other libraries focused on annotation or signature, creating a PDF experience tailored for your users' needs</p>
</li>
</ul>
<p>PDF.js is often used in websites, web apps, and custom projects where you just want to keep everything in the browser. It’s a solid pick if you want to display documents in a way that just works for everyone. As of July 2025,<code>pdfjs-dist</code> has over 51,400 stars with over 390 contributors on GitHub and an average weekly downloads count of over 4,000,000.</p>
<p><a target="_blank" href="https://github.com/mozilla/pdf.js">https://github.com/mozilla/pdf.js</a></p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/em9q3yzykr0plhwyliee.png" alt="Screenshot of PDF.js" class="image--center mx-auto" /></p>
<hr />
<h3 id="heading-vue-pdf-embed">vue-pdf-embed</h3>
<p><code>vue-pdf-embed</code>, built on top of PDF.js, offers Vue developers an easy way to embed PDF viewing capabilities into any page or dashboard. It provides an easy-to-use component designed for Vue 2 and Vue 3 to display PDFs without complex setup.</p>
<p><strong>Key Features</strong></p>
<ul>
<li><p>Controlled rendering: Letting you manage how and when pages display.</p>
</li>
<li><p>Support for password-protected PDF: Keep sensitive files secure and accessible only to the right people.</p>
</li>
<li><p>Selectable text: Great for users who need to copy or search document content.</p>
</li>
<li><p>Support annotation layer: PDF with annotations can be displayed easily.</p>
</li>
</ul>
<p>If you need just the basics or want a lightweight viewer with proven usage, this library fits the bill. As of July 2025,<code>vue-pdf-embed</code> has over 890 stars, 25 contributors, and an average weekly downloads count of over 59,000.</p>
<p><a target="_blank" href="https://github.com/hrynko/vue-pdf-embed">https://github.com/hrynko/vue-pdf-embed</a></p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ulp0c4nw9e78ne50mg0v.png" alt="Screenshot of vue-pdf-embed" class="image--center mx-auto" /></p>
<h3 id="heading-tato30vue-pdf">@tato30/vue-pdf</h3>
<p><code>@tato30/vue-pdf</code> is a popular Vue wrapper for Mozilla’s PDF.js. It brings deep PDF rendering directly into Vue projects, allowing you to avoid custom wiring with PDF.js’s raw API. It supports many core features of PDF.js and makes it easier to integrate into Vue or Nuxt applications.</p>
<p><strong>Key Features</strong></p>
<ul>
<li><p>Simple integration if your app is already built on Vue 3</p>
</li>
<li><p>Provide functions like search, zoom level and rotate</p>
</li>
<li><p>Render control for text, annotations, and optional layers</p>
</li>
<li><p>Allow custom watermark on PDF pages to protect your content</p>
</li>
</ul>
<p>If you're looking for than a simple PDF reader, this library is great for complex interactions. As of July 2025,<code>@tato30/vue-pdf</code> has over 589 stars with 9 contributors on GitHub and an average weekly downloads count of over 25,000.</p>
<p><a target="_blank" href="https://github.com/TaTo30/vue-pdf">https://github.com/TaTo30/vue-pdf</a></p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lxxa25770yq1x56t8w6r.png" alt="Screenshot of @tato30/vue-pdf" class="image--center mx-auto" /></p>
<h3 id="heading-vue-pdf">vue-pdf</h3>
<p>The <code>vue-pdf</code> library (not to be confused with others with similar names) is an older lightweight wrapper around PDF.js, specifically tailored for Vue applications. By using <code>vue-pdf</code>, Vue developers can enjoy the benefits of PDF.js without needing to manage the complex JavaScript integration manually.</p>
<p><strong>Key Features</strong></p>
<ul>
<li><p>Fast single-page or multi-page PDF rendering</p>
</li>
<li><p>Simple navigation controls, print and zoom</p>
</li>
<li><p>Provide events for loading, progress, and error handling</p>
</li>
</ul>
<p>Vue-pdf is ideal for applications that require basic PDF display. It's a practical option for small projects and MVPs where ease of use and quick implementation are prioritized. As of July 2025,<code>vue-pdf</code> as over 2,300 stars with 20 contributors on GitHub and an average weekly downloads count of over 17,000.</p>
<p><a target="_blank" href="https://github.com/FranckFreiburger/vue-pdf">https://github.com/FranckFreiburger/vue-pdf</a></p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t5j4ydq6i8bsk5wr0f1h.png" alt="Screenshot of vue-pdf" class="image--center mx-auto" /></p>
<blockquote>
<p>⚠️ The library has not been updated since Jun 2021 so use it with caution. Remember to update <code>pdf-dist</code> version to avoid potential security and compatibility concerns.</p>
</blockquote>
<hr />
<h2 id="heading-open-source-pdf-annotation-libraries-for-vue">Open-Source PDF Annotation Libraries for Vue</h2>
<p>Modern applications demand more than just displaying PDFs. Users now expect to draw, highlight, and leave comments on documents, all inside the browser. Getting annotation tools right can make or break PDF Viewing experience in a Vue.js project. Here's how three powerful open-source options stack up for bringing annotations to life in Vue apps.</p>
<h3 id="heading-pdf-lib">pdf-lib</h3>
<p>If you are looking to programmatically annotate PDFs in your Vue project, <code>pdf-lib</code> stands out. This open-source JavaScript library lets you work with PDFs in the browser and on the server. It’s not just a PDF annotator, it supports form creation, content editing, and even digital signatures.</p>
<p><strong>Key Features</strong></p>
<ul>
<li><p>Add new shapes, signatures, or freehand scribbles.</p>
</li>
<li><p>Highlight text sections in a way that’s easy for users to spot later.</p>
</li>
<li><p>Attach notes or pop-up comments to any part of the PDF.</p>
</li>
<li><p>Has no external dependencies, keeping your bundle size manageable and integrations simple.</p>
</li>
</ul>
<p>With a clean API, Vue coders can use <code>pdf-lib</code> to create or update complex annotations dynamically, storing them in the user’s browser or syncing them with a backend as needed. As of July 2025, <code>pdf-lib</code> has over 7,700 stars with 42 contributors on GitHub and an average weekly downloads count of over 1,480,000.</p>
<p><a target="_blank" href="https://github.com/Hopding/pdf-lib">https://github.com/Hopding/pdf-lib</a></p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ew666grc1mkuy357fcot.png" alt="Screenshot of pdf-lib" class="image--center mx-auto" /></p>
<blockquote>
<p>⚠️ The library has not been updated since Nov 2021 so use it with caution. There is a <a target="_blank" href="https://github.com/cantoo-scribe/pdf-lib">forked</a> version but I'm unable to verify its current status.</p>
</blockquote>
<h3 id="heading-sinatayebatipdfjs-annotation">sinatayebati/pdfjs-annotation</h3>
<p>For devs who want a faster setup, sinatayebati/pdfjs-annotation offers a Vue-based annotation UI, tightly wrapped around Mozilla PDF.js. You get a ready-to-use PDF Viewer plus a complete set of annotation features built right in.</p>
<p><strong>Key Features</strong></p>
<ul>
<li><p>Annotation tools includes shapes, highlights, free text and more</p>
</li>
<li><p>Designed to overlay on PDF.js within a Vue context, so your data stays reactive and easy to sync.</p>
</li>
<li><p>Annotation widgets and toolbars are part of the package, so you don't have to build them from scratch.</p>
</li>
</ul>
<p>This wrapper takes a lot of guesswork out of document enhancement. You can enrich PDF files with highlights or notes and never leave the app’s single-page flow.</p>
<p><a target="_blank" href="https://github.com/sinatayebati/pdfjs-annotation">https://github.com/sinatayebati/pdfjs-annotation</a></p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8bwvtpux3nhm0rmfxfw9.png" alt="Screenshot of sinatayebati/pdfjs-annotation" class="image--center mx-auto" /></p>
<h3 id="heading-thats-right-mozilla-pdfjs">That's right, Mozilla PDF.js</h3>
<p>Did you know that PDF.js has started rolling out annotation editor back in <a target="_blank" href="https://github.com/mozilla/pdf.js/releases/tag/v3.0.279">v3.0.279</a> released in October 2022. Just for context, the most recent version of PDF.js is <a target="_blank" href="https://github.com/mozilla/pdf.js/releases/tag/v5.3.93">5.3.93</a>. Surprising there isn't a lot information on how to utilize annotation functions in PDF.js</p>
<p><strong>Key Features</strong></p>
<ul>
<li><p>Highlight, underline, strikethrough text or areas for instant visual cues</p>
</li>
<li><p>Drop virtual notes anywhere in your PDF to collaborate easily</p>
</li>
<li><p>Add new shapes, images, or free text to enrich your PDF file</p>
</li>
</ul>
<p>Knowing how to integrate and extend PDF.js can turn your app from a simple PDF viewer into a dynamic document experience that users will love.</p>
<p>Demo: <a target="_blank" href="https://mozilla.github.io/pdf.js/web/viewer.html">https://mozilla.github.io/pdf.js/web/viewer.html</a></p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n33clbithjzz5nafjw6e.png" alt="Screenshot of PDF.js with annotations" class="image--center mx-auto" /></p>
<hr />
<h2 id="heading-how-combining-libraries-boosts-pdf-functionality">How Combining Libraries Boosts PDF Functionality</h2>
<p>If a single library does not all of your use cases, you could consider combining libraries in your Vue project. Think of your PDF stack like LEGO blocks. You can mix libraries—one for fast viewing, one for deep annotation, another for e-signatures or forms—to create the setup your project actually needs.</p>
<p><strong>For instance:</strong></p>
<ul>
<li><p>Start with <code>vue-pdf-embed</code> for light, fast viewing inside dashboards</p>
</li>
<li><p>Bring in <code>pdf-lib</code> if you want to annotate PDF or handle form data behind the scenes</p>
</li>
</ul>
<p>This mix-and-match method keeps your app flexible. When a new requirement or feature comes along, you just swap or add another piece, rather than rebuilding from scratch. Combining open-source libraries helps you tailor the user experience and stay in control.</p>
<hr />
<h2 id="heading-how-to-choose-the-right-library-for-your-project">How to Choose the Right Library for Your Project</h2>
<p>With so many open-source options available, making the right choice starts with focusing on what your users need and what works for your workflow. A good fit saves you time, keeps your app smooth, and lets your users read, search, and mark up documents without any distractions:</p>
<ol>
<li><p><strong>Vue Compatibility</strong> - Libraries based on Vue take advantage of hooks, props, and state for smooth integration. Generic JS tools may need more setup or “glue code.”</p>
</li>
<li><p><strong>Know Your Use Cases</strong> - By mapping out your core requirements, you won’t get distracted by extra features you’ll never use. You’ll hone in on what matters.</p>
</li>
<li><p>Community and Documentation - A powerful library is only as good as its documentation and community. Scan GitHub stars and check for active issues.</p>
</li>
<li><p><strong>Performance</strong> - Performance matters, especially for web apps that serve large or image-heavy documents. Explore if the libraries uses techniques like lazy loading or virtualization to keep things fast</p>
</li>
</ol>
<hr />
<h2 id="heading-real-world-testing">Real-World Testing</h2>
<p>Finally, never trust a demo alone. Pull in a few sample PDFs from your users with a quick prototype. Try different annotation workflows. Make sure font rendering, zoom, and navigation all work as expected. A little time spent testing now can save you endless fixes down the road.</p>
<hr />
<p>If you liked this article, take a look at a library for <a target="_blank" href="https://www.vue-pdf-viewer.dev/?utm_source=blog&amp;utm_medium=referral&amp;utm_content=6-open-source-pdf-viewer-and-annotation-libraries-every-vue-developers-should-know">Vue PDF</a>, a modern PDF viewing solution built specifically for Vue 3 apps. It’s designed to drop smoothly into your Vue ecosystem, whether you’re using PrimeVue, Vuetify, or your own custom UI setup.</p>
<p>Vue PDF Viewer helps you build polished document experiences without starting from scratch. Features include:</p>
<ul>
<li><p>Vue 3 Composition API support</p>
</li>
<li><p>Responsive UI with thumbnails, toolbars, and other tools such as highlights, zoom and search</p>
</li>
<li><p>Works with both local and remote files</p>
</li>
<li><p>Clean APIs and typed props for full developer control</p>
</li>
</ul>
<p>Vue PDF Viewer is actively maintained and developer-focused. If you’re building serious document functionality in Vue, it’s worth a look 🙏</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8nu0lkpijspajsuzw7f4.png" alt="Screenshot of Vue PDF Viewer" /></p>
]]></content:encoded></item><item><title><![CDATA[🚀 PDF Viewer in PrimeVue using @vue-pdf-viewer 💡]]></title><description><![CDATA[PrimeVue gives Vue.js developers flexible UI components for building interactive user interfaces for fast Vue.js development. But when you need to build a PDF Viewer, native PDF rendering requires extra support. @vue-pdf-viewer stands out for its spe...]]></description><link>https://blog.vue-pdf-viewer.dev/pdf-viewer-in-primevue-using-vue-pdf-viewer</link><guid isPermaLink="true">https://blog.vue-pdf-viewer.dev/pdf-viewer-in-primevue-using-vue-pdf-viewer</guid><category><![CDATA[Vue.js]]></category><category><![CDATA[Nuxt]]></category><category><![CDATA[Nuxt.js]]></category><category><![CDATA[PrimeVue]]></category><category><![CDATA[pdfjs-dist]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[TypeScript]]></category><category><![CDATA[Frontend Development]]></category><category><![CDATA[Web Development]]></category><dc:creator><![CDATA[watcharakorn]]></dc:creator><pubDate>Tue, 19 Aug 2025 06:05:32 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1755583407541/d39bec51-3c71-4336-9436-ec7da5f79f1f.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>PrimeVue gives Vue.js developers flexible UI components for building interactive user interfaces for fast Vue.js development. But when you need to build a PDF Viewer, native PDF rendering requires extra support. <code>@vue-pdf-viewer</code> stands out for its speed and ease of integration.</p>
<p>This guide explains how to use both PrimeVue and <code>@vue-pdf-viewer</code> together to display PDFs right in your Vue app. Set up a powerful vue pdf experience for your users, no matter how big your project grows.</p>
<p><img src="https://media1.giphy.com/media/v1.Y2lkPTc5MGI3NjExNTMzYTUxdDBuZ2NwMjg1cDNkOXQ4ZnUwMzAzM3FsYXk5NWg1bnpmaCZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/XBLOKUWPnzm6U8gQWS/giphy.gif" alt="Gif of get started" class="image--center mx-auto" /></p>
<hr />
<h2 id="heading-step-1-set-up-a-vue-3-project">Step 1: Set up a Vue 3 Project</h2>
<p>Start by setting up a new Vue 3 project using your preferred package manager (bun, pnpm, npm, yarn). Here’s an example using bun:</p>
<h3 id="heading-create-a-new-vite-project">Create a new Vite project</h3>
<pre><code class="lang-sh">bun create vite
</code></pre>
<ul>
<li><p>Vite will prompt you for a project name and package name.</p>
</li>
<li><p>When Vite asks for a framework, choose Vue.</p>
</li>
<li><p>For the variant, select TypeScript (Vue + TS).</p>
</li>
</ul>
<hr />
<h2 id="heading-step-2-install-primevue-and-vue-pdf-viewer">Step 2: Install PrimeVue and Vue PDF Viewer</h2>
<h3 id="heading-install-primevue">Install PrimeVue</h3>
<p>Install PrimeVue for UI elements:</p>
<pre><code class="lang-sh">bun add primevue @primeuix/themes
</code></pre>
<h3 id="heading-install-vue-pdf-viewer">Install Vue PDF Viewer</h3>
<p>Next, install the Vue PDF Viewer package, <code>@vue-pdf-viewer/viewer</code>:</p>
<pre><code class="lang-sh">bun add @vue-pdf-viewer/viewer
</code></pre>
<p>For more information on how to install Vue PDF Viewer using other package managers, check out the <a target="_blank" href="https://docs.vue-pdf-viewer.dev/introduction/getting-started.html#installation?utm_source=blog&amp;utm_medium=referral&amp;utm_content=pdf-viewer-in-primevue-using-vue-pdf-viewer">Installation</a> guide.</p>
<hr />
<h2 id="heading-step-3-set-up-primevue">Step 3: Set up PrimeVue</h2>
<h3 id="heading-configure-the-maints">Configure the main.ts</h3>
<p>To set up the default configuration, PrimeVue plugin is required to be installed as an application plugin. It's lightweight and utilized for configuration purposes only.</p>
<pre><code class="lang-ts"><span class="hljs-comment">// main.ts</span>
<span class="hljs-keyword">import</span> { createApp } <span class="hljs-keyword">from</span> <span class="hljs-string">'vue'</span>
<span class="hljs-keyword">import</span> App <span class="hljs-keyword">from</span> <span class="hljs-string">'./App.vue'</span>
<span class="hljs-keyword">import</span> PrimeVue <span class="hljs-keyword">from</span> <span class="hljs-string">'primevue/config'</span> <span class="hljs-comment">// 👈 here</span>

<span class="hljs-keyword">const</span> app = createApp(App)
app.use(PrimeVue)
app.mount(<span class="hljs-string">'#app'</span>)
</code></pre>
<p>Verify your setup by adding a component to the the application. In this case, I will add a button and dialog. Each component can be imported and registered individually so that you can include only what you use for bundle optimization.</p>
<pre><code class="lang-ts"><span class="hljs-comment">// main.ts</span>
<span class="hljs-keyword">import</span> { createApp } <span class="hljs-keyword">from</span> <span class="hljs-string">'vue'</span>
<span class="hljs-keyword">import</span> App <span class="hljs-keyword">from</span> <span class="hljs-string">'./App.vue'</span>
<span class="hljs-keyword">import</span> PrimeVue <span class="hljs-keyword">from</span> <span class="hljs-string">'primevue/config'</span>
<span class="hljs-keyword">import</span> Button <span class="hljs-keyword">from</span> <span class="hljs-string">'primevue/button'</span> <span class="hljs-comment">// 👈 here</span>
<span class="hljs-keyword">import</span> Dialog <span class="hljs-keyword">from</span> <span class="hljs-string">'primevue/dialog'</span> <span class="hljs-comment">// 👈 here</span>

<span class="hljs-keyword">const</span> app = createApp(App)
app.use(PrimeVue, {
  theme: {
    preset: Aura <span class="hljs-comment">// 👈 here</span>
  }
})

app.component(<span class="hljs-string">'Button'</span>, Button) <span class="hljs-comment">// 👈 here</span>
app.component(<span class="hljs-string">'Dialog'</span>, Dialog) <span class="hljs-comment">// 👈 here</span>
app.mount(<span class="hljs-string">'#app'</span>)
</code></pre>
<pre><code class="lang-typescript">&lt;!-- App.vue --&gt;
&lt;script setup lang=<span class="hljs-string">"ts"</span>&gt;
<span class="hljs-keyword">const</span> visible = ref(<span class="hljs-literal">false</span>)
&lt;/script&gt;

&lt;template&gt;
  &lt;Button label=<span class="hljs-string">"Show"</span> <span class="hljs-meta">@click</span>=<span class="hljs-string">"visible = true"</span> /&gt;
  &lt;Dialog v-model:visible=<span class="hljs-string">"visible"</span> modal header=<span class="hljs-string">"Dialog title"</span> :style=<span class="hljs-string">"{ width: '80vw' }"</span>&gt;
    dialog content
  &lt;/Dialog&gt;
&lt;/template&gt;
</code></pre>
<hr />
<h2 id="heading-step-4-create-a-reusable-vue-pdf-viewer-component">Step 4: Create a Reusable Vue PDF Viewer Component</h2>
<p>Next, let’s build a reusable PdfViewer component using <code>&lt;VPdfViewer&gt;</code> from <code>@vue-pdf-viewer/viewer</code>.</p>
<p>Create a file inside your components directory.</p>
<pre><code class="lang-typescript">&lt;!-- PdfViewer.vue --&gt;
&lt;script setup lang=<span class="hljs-string">"ts"</span>&gt;
<span class="hljs-keyword">import</span> { VPdfViewer, VPVBaseProps } <span class="hljs-keyword">from</span> <span class="hljs-string">'@vue-pdf-viewer/viewer'</span>

<span class="hljs-keyword">const</span> props = defineProps({
  ...VPVBaseProps
})
&lt;/script&gt;

&lt;template&gt;
  &lt;div style=<span class="hljs-string">"width: 1028px; height: 700px; margin: 0 auto"</span>&gt;
    &lt;VPdfViewer v-bind=<span class="hljs-string">"props"</span> /&gt;
  &lt;/div&gt;
&lt;/template&gt;
</code></pre>
<p>Here’s what each part does:</p>
<ul>
<li><p><strong>VPdfViewer</strong> is the core PDF rendering component</p>
</li>
<li><p><strong>VPVBaseProps</strong> includes all supported props (like src, page, zoom) so we can pass them in from a parent component.</p>
</li>
<li><p>We define the props using <strong>defineProps</strong> and spread VPVBaseProps. This makes the component flexible and lets you bind any supported viewer prop without redefining them manually.</p>
</li>
<li><p>We render <code>&lt;VPdfViewer&gt;</code> with <strong>v-bind="props"</strong>. This automatically forwards all props from the parent to the viewer component, so it works like a wrapper you can reuse anywhere.</p>
</li>
</ul>
<p>This setup keeps your PdfViewer.vue clean and flexible. You can now reuse it anywhere with different PDFs, zoom levels, pages, and more.</p>
<h3 id="heading-use-the-pdfviewer-in-appvue">Use the PdfViewer in App.vue</h3>
<p>For this use case, a Vue PDF Viewer component is displayed in a PrimeVue Dialog component.</p>
<p>First, import and register the PrimeVue Dialog component. Next, integrate the PdfViewer component into your Vue app which will be displayed in a dialog:</p>
<pre><code class="lang-typescript">&lt;!-- App.vue --&gt;
&lt;script setup lang=<span class="hljs-string">"ts"</span>&gt;
<span class="hljs-keyword">import</span> { ref } <span class="hljs-keyword">from</span> <span class="hljs-string">'vue'</span>
<span class="hljs-keyword">import</span> PdfViewer <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/PdfViewer.vue'</span>
<span class="hljs-keyword">const</span> visible = ref(<span class="hljs-literal">false</span>)

<span class="hljs-keyword">const</span> pdfSrc =
<span class="hljs-string">'https://raw.githubusercontent.com/mozilla/pdf.js/ba2edeae/web/compressed.tracemonkey-pldi-09.pdf'</span>
&lt;/script&gt;

&lt;template&gt;
  &lt;Button label=<span class="hljs-string">"Show"</span> <span class="hljs-meta">@click</span>=<span class="hljs-string">"visible = true"</span> /&gt;
  &lt;Dialog
    v-model:visible=<span class="hljs-string">"visible"</span>
    modal
    <span class="hljs-keyword">class</span>=<span class="hljs-string">"my-dialog"</span>
    :style=<span class="hljs-string">"{ width: '55rem', height: '55rem' }"</span>
  &gt;
    &lt;template #header&gt;
      &lt;p :style=<span class="hljs-string">"{ textAlign: 'center' }"</span>&gt;Preview PDF&lt;/p&gt;
    &lt;/template&gt;
    &lt;PdfViewer :src=<span class="hljs-string">"pdfSrc"</span> :initial-scale=<span class="hljs-string">"1"</span> :style=<span class="hljs-string">"{ width: '100%', height: '100%' }"</span> /&gt;
    &lt;template #footer&gt;
      &lt;Button label=<span class="hljs-string">"Close"</span> <span class="hljs-meta">@click</span>=<span class="hljs-string">"visible = false"</span> /&gt;
    &lt;/template&gt;
  &lt;/Dialog&gt;
&lt;/template&gt;
</code></pre>
<p>If you open the dialog, Vue PDF Viewer will render the PDF content. However, if you click on the print icon, the print preview will not be displayed correctly. To fix this issue, you can add styles to <code>@media print</code>:</p>
<pre><code class="lang-typescript">&lt;script setup lang=<span class="hljs-string">"ts"</span>&gt;
<span class="hljs-keyword">import</span> { ref } <span class="hljs-keyword">from</span> <span class="hljs-string">'vue'</span>
<span class="hljs-keyword">import</span> PdfViewer <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/PdfViewer.vue'</span>
<span class="hljs-keyword">const</span> visible = ref(<span class="hljs-literal">false</span>)

<span class="hljs-keyword">const</span> pdfSrc =
<span class="hljs-string">'https://raw.githubusercontent.com/mozilla/pdf.js/ba2edeae/web/compressed.tracemonkey-pldi-09.pdf'</span>
&lt;/script&gt;

&lt;template&gt;
  &lt;Button label=<span class="hljs-string">"Show"</span> <span class="hljs-meta">@click</span>=<span class="hljs-string">"visible = true"</span> /&gt;
  &lt;Dialog
    v-model:visible=<span class="hljs-string">"visible"</span>
    modal
    <span class="hljs-keyword">class</span>=<span class="hljs-string">"my-dialog"</span>
    :style=<span class="hljs-string">"{ width: '55rem', height: '55rem' }"</span>
  &gt;
    &lt;template #header&gt;
      &lt;p :style=<span class="hljs-string">"{ textAlign: 'center' }"</span>&gt;Preview PDF&lt;/p&gt;
    &lt;/template&gt;
    &lt;PdfViewer :src=<span class="hljs-string">"pdfSrc"</span> :initial-scale=<span class="hljs-string">"1"</span> :style=<span class="hljs-string">"{ width: '100%', height: '100%' }"</span> /&gt;
    &lt;template #footer&gt;
      &lt;Button label=<span class="hljs-string">"Close"</span> <span class="hljs-meta">@click</span>=<span class="hljs-string">"visible = false"</span> /&gt;
    &lt;/template&gt;
  &lt;/Dialog&gt;
&lt;/template&gt;

&lt;!-- add style to prevent print pdf that render on dialog --&gt;
&lt;style&gt;
<span class="hljs-meta">@media</span> print {
  <span class="hljs-comment">/* Hide the dialog mask */</span>
  .p-dialog-mask {
    display: none !important;
  }
  <span class="hljs-comment">/* Style the nearest ancestor of the Vue PDF Viewer container */</span>
  .p-dialog-content {
    position: relative; <span class="hljs-comment">/* Ensure it's not fixed or absolute */</span>
    display: block !important; <span class="hljs-comment">/* Ensure it's visible */</span>
    overflow: visible; <span class="hljs-comment">/* Ensure no content is clipped */</span>
  }
}
&lt;/style&gt;
</code></pre>
<p>Here’s what’s happening:</p>
<ul>
<li><p><strong>PdfViewer</strong> component is the wrapper we created earlier using VPdfViewer under the hood.</p>
</li>
<li><p>The PdfViewer component is added inside <code>Dialog</code></p>
</li>
<li><p>We defined a sample <strong>pdfSrc</strong> string. This is the URL of the PDF you want to display. You can replace it with your own file (local or remote).</p>
</li>
<li><p>We pass <strong>:src="pdfSrc"</strong> as a prop to <code>&lt;PdfViewer&gt;</code>. This binds the PDF file URL to the viewer component, which will take care of rendering it.</p>
</li>
</ul>
<blockquote>
<p>For more information on how <code>@vue-pdf-viewer</code> handles printing, here is the tutorial of <a target="_blank" href="https://docs.vue-pdf-viewer.dev/tutorial/displaying-print-preview-from-any-dialog.html?utm_source=blog&amp;utm_medium=referral&amp;utm_content=pdf-viewer-in-primevue-using-vue-pdf-viewer">Printing via PrimeVue Dialog</a>.</p>
</blockquote>
<p>And that’s it, you now have a working PDF viewer inside your Vue app! You can reuse this setup across different pages or wrap it inside a dialog for modal-style viewing if needed.</p>
<p>If you'd like to see the full codes for this example, check out the <a target="_blank" href="https://stackblitz.com/edit/vitejs-vite-kpm14jiv?file=src%2FApp.vue">Stackblitz</a> link for this article.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/al1o7f585vqvuxqlarhu.gif" alt="Image description" /></p>
<hr />
<h2 id="heading-looking-for-a-faster-setup">Looking for a Faster Setup?</h2>
<p>If you want to skip boilerplate and get straight to building, check out Vue PDF Viewer <a target="_blank" href="https://docs.vue-pdf-viewer.dev/usage-guide/starter-toolkit.html?utm_source=blog&amp;utm_medium=referral&amp;utm_content=pdf-viewer-in-primevue-using-vue-pdf-viewer">Starter Toolkit</a>.</p>
<p>It includes ready-to-use templates for:</p>
<ul>
<li><p>Vue: Composition API (JavaScript / TypeScript)</p>
</li>
<li><p>Vue: Options API (JavaScript / TypeScript)</p>
</li>
<li><p>Nuxt (TypeScript)</p>
</li>
<li><p>Vue: SSR (TypeScript)</p>
</li>
<li><p>PrimeVue</p>
</li>
<li><p>Quasar</p>
</li>
<li><p>VitePress</p>
</li>
<li><p>Ionic</p>
</li>
</ul>
<p>Each template comes with a clean folder structure and sample code so you can build a PDF viewer quickly without spending hours configuring dependencies. Just clone, customize, and go. 🚀</p>
<hr />
<h2 id="heading-conclusion">Conclusion</h2>
<p>Now that you have the files in place and the dependencies correctly installed, you now have a basic Vue PDF application set up that plays well with PrimeVue. You can customize the viewer further by exploring the options and features provided by <a target="_blank" href="https://www.npmjs.com/package/@vue-pdf-viewer/viewer">@vue-pdf-viewer/viewer</a>.</p>
<p>Explore the full list of <a target="_blank" href="https://docs.vue-pdf-viewer.dev/component-api/props.html?utm_source=blog&amp;utm_medium=referral&amp;utm_content=pdf-viewer-in-primevue-using-vue-pdf-viewer">props and events</a> available in <code>@vue-pdf-viewer/viewer</code>. Pair these features with PrimeVue’s UI components, and you’ll be able to offer a user-friendly, feature-packed document viewer tailored to your users’ needs.</p>
<p>Hope this helped you get started! If you build something with it or run into questions, feel free to drop a comment. I’d love to hear how you’re using Vue PDF Viewer. 🔧📄</p>
<p><img src="https://media.giphy.com/media/v1.Y2lkPWVjZjA1ZTQ3ZmUzcHBvYzNobzhpenljbDhscXo5dWtpdWh4YmVncGN2dW9yNWZkNCZlcD12MV9naWZzX3NlYXJjaCZjdD1n/l4KibK3JwaVo0CjDO/giphy.gif" alt="Gif of cat sliding down stairs" class="image--center mx-auto" /></p>
]]></content:encoded></item><item><title><![CDATA[✨ Building a PDF Viewer in Nuxt with PDF.js, vue-pdf-embed, vue-pdf and Vue PDF Viewer 🚀]]></title><description><![CDATA[It has been a year since my previous article on ✨Building a PDF Viewer for Vue.js with PDF.js, vue3-pdf-app and more 🚀, where I walked through methods like iFrame, opening PDFs in a new tab, using PDF.js or vue3-pdf-app.
Since Nuxt framework is used...]]></description><link>https://blog.vue-pdf-viewer.dev/building-a-pdf-viewer-in-nuxt-with-pdfjs-vue-pdf-embed-vue-pdf-and-vue-pdf-viewer</link><guid isPermaLink="true">https://blog.vue-pdf-viewer.dev/building-a-pdf-viewer-in-nuxt-with-pdfjs-vue-pdf-embed-vue-pdf-and-vue-pdf-viewer</guid><category><![CDATA[vue-pdf-embed]]></category><category><![CDATA[vue-pdf]]></category><category><![CDATA[vue pdf viewer]]></category><category><![CDATA[Vue.js]]></category><category><![CDATA[Nuxt.js]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[TypeScript]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[Frontend Development]]></category><category><![CDATA[pdfjs-dist]]></category><category><![CDATA[pdfjs]]></category><category><![CDATA[pdf viewer]]></category><dc:creator><![CDATA[watcharakorn]]></dc:creator><pubDate>Tue, 01 Jul 2025 10:23:18 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1751365273288/d8286e97-107e-424b-82fa-35f6d062f1ea.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>It has been a year since my previous article on <a target="_blank" href="https://blog.vue-pdf-viewer.dev/building-a-pdf-viewer-for-vuejs-with-pdfjs-vue3-pdf-app-and-more">✨Building a PDF Viewer for Vue.js with PDF.js, vue3-pdf-app and more 🚀</a>, where I walked through methods like iFrame, opening PDFs in a new tab, using PDF.js or vue3-pdf-app.</p>
<p>Since Nuxt framework is used extensively in the Vue community, I thought it would be interesting to look into how you can build a PDF viewer in Nuxt.</p>
<p>In this article, I will be sharing with you four ways to render PDFs in Nuxt using: <strong>PDF.js</strong>, <strong>vue-pdf-embed</strong>, <code>@tato30/vue-pdf</code>, and <strong>Vue PDF Viewer</strong>. I will also break down the pros and cons of each so you can pick what fits your project best.</p>
<p><img src="https://media0.giphy.com/media/v1.Y2lkPTc5MGI3NjExOXE5dDJzNjB2OGFvYmw0OGxrZ3hsa3lnZXNiN2N0cTYxOWVyZ3VsayZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/IhT10cz8InTQfKj1Tt/giphy.gif" alt="Gif to let's go" class="image--center mx-auto" /></p>
<hr />
<h2 id="heading-how-is-nuxt-different-from-vuejs">How is Nuxt different from Vue.js?</h2>
<p>Vue.js is great for building interactive interfaces, but when your app grows, you often end up stitching together routing, server-side rendering (SSR), and deployment setup on your own.</p>
<p>That’s where Nuxt steps in. It’s a framework built on top of Vue.js that adds SSR, static site generation, automatic routing, and performance optimizations out of the box, so you can focus on building your site's features.</p>
<p>Both Vue and Nuxt uses the same core ideas, but Nuxt gives you more structure for large projects. If you want to scale your site or improve SEO, Nuxt saves time and reduces setup headaches.</p>
<hr />
<h2 id="heading-vue-pdf-viewer-flexible-and-powerful-vuejs-pdf-component">Vue PDF Viewer: Flexible and Powerful Vue.js PDF Component</h2>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nsoujnrct177r7qikll8.png" alt="Screenshot of Vue PDF Viewer" class="image--center mx-auto" /></p>
<p>Just a quick background of what I’m working on. If you’re building a PDF experience into your Vue or Nuxt app, check out <a target="_blank" href="https://www.vue-pdf-viewer.dev/?utm_source=blog&amp;utm_content=building-a-pdf-viewer-in-nuxt-with-pdfjs-vue-pdf-embed-vue-pdf-and-vue-pdf-viewer">Vue PDF Viewer</a>.</p>
<p>It has over 20 features component that lets users view and interact with PDFs right on your site. With built-in localization, theming, and responsive design, it’s made for teams who care about UX and maintainability.</p>
<p>I’d love your feedback and support, it helps me keep improving the tool and creating helpful content for the Vue community ❤️</p>
<hr />
<h2 id="heading-method-1-pdfjs">Method 1: PDF.js</h2>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1x9sf13ug91igc3wgf88.png" alt="Screenshot of PDF.js" class="image--center mx-auto" /></p>
<p><a target="_blank" href="https://mozilla.github.io/pdf.js/"><strong>PDF.js</strong></a> is a powerful JavaScript library from Mozilla that allows rendering and interaction of PDFs directly in web browsers. PDF.js is framework agnostic and can be used in any Javascript framework such as Angular, React and Vue.</p>
<p>In Nuxt, you can use PDF.js by:</p>
<ol>
<li><p>Install the PDF.js library via npm.</p>
</li>
<li><p>Create a component to display the PDF viewer.</p>
</li>
<li><p>Incorporate PDF.js into the component to render PDF files.</p>
</li>
</ol>
<p>Here is the <a target="_blank" href="https://stackblitz.com/edit/nuxt-starter-k3f14uhv?file=app.vue">link</a> to the code sample.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/up2mxgsi2b14d4i4qft4.png" alt="PDF.js Demo for Nuxt" class="image--center mx-auto" /></p>
<h3 id="heading-pros">Pros</h3>
<ul>
<li><p><strong>Reliable</strong>: Developed by Mozilla and supported by the Firefox team.</p>
</li>
<li><p><strong>Active development</strong>: Regular updates and maintenance by Mozilla.</p>
</li>
<li><p><strong>Full control over rendering</strong>: You can customize rendering (zoom, page navigation, annotation, etc.).</p>
</li>
<li><p><strong>Supports advanced features</strong>: Such as rendering page by page, custom UI, highlighting, and more.</p>
</li>
<li><p><strong>Flexible without relying on external UI</strong>: You can build your own UI viewer as needed.</p>
</li>
<li><p><strong>Big community</strong>: Great for fixing issues and debugging on your own.</p>
</li>
</ul>
<h3 id="heading-cons">Cons</h3>
<ul>
<li><p><strong>Disorganized documentation</strong>: Not user-friendly technical document</p>
</li>
<li><p><strong>More complex to use</strong>: Require more code, including handling DOM and canvas</p>
</li>
<li><p><strong>Steep learning curve</strong>: Need to understand the inner workings of PDF.js</p>
</li>
<li><p><strong>Not a Vue component</strong>: Have to write a wrapper or integration for it to work well in Nuxt</p>
</li>
</ul>
<hr />
<h2 id="heading-method-2-vue-pdf-embed">Method 2: vue-pdf-embed</h2>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qltylyh1x1clu8nunms2.png" alt="Screenshot of vue-pdf-embed" class="image--center mx-auto" /></p>
<p><a target="_blank" href="https://github.com/hrynko/vue-pdf-embed"><strong>vue-pdf-embed</strong></a> simplifies the process of displaying PDF files in Vue or Nuxt applications. It provides an easy-to-use component to display PDFs without complex setup.</p>
<p>To use vue-pdf-embed in Nuxt, follow these steps:</p>
<ol>
<li><p>Install the vue-pdf-embed library via npm.</p>
</li>
<li><p>Import and use the component in your App to display the PDF.</p>
</li>
<li><p>Set the URL or Path of the PDF file you want to display.</p>
</li>
</ol>
<p>Here is the <a target="_blank" href="https://stackblitz.com/edit/nuxt-starter-yqd1sgwq?file=app.vue">link</a> to the code sample.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vnm0l92aqdq57dd8im1h.gif" alt="vue-pdf-embed demo for Nuxt" class="image--center mx-auto" /></p>
<h3 id="heading-pros-1">Pros</h3>
<ul>
<li><p><strong>Quick to use</strong>: Just import and use <code>&lt;VuePdfEmbed :source="..." /&gt;</code> (no need to render canvas manually).</p>
</li>
<li><p><strong>Ideal for general users or simple tasks</strong>: Perfect for simple PDF previews.</p>
</li>
<li><p><strong>Lightweight</strong>: Minimal overhead, especially if you don't need a custom UI.</p>
</li>
</ul>
<h3 id="heading-cons-1">Cons</h3>
<ul>
<li><p><strong>No SSR support</strong>: Does not work in Nuxt’s server-side rendering due to reliance on <code>window</code> and <code>canvas</code>.</p>
</li>
<li><p><strong>Minimal customization/features</strong>: Rendering logic and styling options are limited.</p>
</li>
<li><p><strong>Not suitable for complex PDF viewers</strong>: Lacks built-in search, zoom, or multi-page navigation.</p>
</li>
<li><p><strong>Lack of documentation</strong>: Advanced usage guides and tutorials are not provided.</p>
</li>
<li><p><strong>Smaller community</strong>: Support and troubleshooting might require waiting for an issue or PR from other users.</p>
</li>
</ul>
<hr />
<h2 id="heading-method-3-tato30vue-pdf">Method 3: @tato30/vue-pdf</h2>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6wbwxxqmpj7thqdtcgxc.png" alt="Screenshot of vue-pdf" class="image--center mx-auto" /></p>
<p><a target="_blank" href="https://github.com/TaTo30/vue-pdf"><strong>@tato30/vue-pdf</strong></a> is a Vue wrapper around Mozilla’s PDF.js that offers a more Vue-friendly way to render PDFs. It supports most core features of PDF.js and makes it easier to integrate into Nuxt applications.</p>
<p>To get started:</p>
<ol>
<li><p>Install <code>@tato30/vue-pdf</code> via npm or yarn.</p>
</li>
<li><p>`Import the component and register it globally or locally.</p>
</li>
<li><p>Use the component in your template and pass the PDF file URL using the src prop.</p>
</li>
</ol>
<p>Here is the link <a target="_blank" href="https://stackblitz.com/edit/nuxt-starter-acyqpadv?file=app.vue,components%2FBasicUsage.client.vue">link</a> for code sample</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xm6vwzx0y0fy4j37ogrr.gif" alt="vue-pdf demo for Nuxt" class="image--center mx-auto" /></p>
<h3 id="heading-pros-2">Pros</h3>
<ul>
<li><p><strong>Vue/Nuxt support</strong>: Fully compatible with Vue and Nuxt using the Composition API.</p>
</li>
<li><p><strong>Simple API</strong>: Easy to use and integrate, even for beginners.</p>
</li>
<li><p><strong>PDF rendering flexibility</strong>: Supports individual page rendering, text layers, and annotation layers.</p>
</li>
<li><p><strong>Support for non-Latin fonts</strong>: With proper setup (e.g. cmaps), it can render PDFs with non-Latin characters.</p>
</li>
</ul>
<h3 id="heading-cons-2">Cons</h3>
<ul>
<li><p><strong>No SSR support</strong>: Rely on browser-specific APIs like <code>window</code> and <code>canvas</code>, which break in Nuxt SSR mode.</p>
</li>
<li><p><strong>No built-in multi-page rendering</strong>: You must manually loop through each page using <code>v-for</code>, which can affect performance.</p>
</li>
<li><p><strong>Lacks built-in UI controls</strong>: No default navigation elements (e.g. next/previous buttons, zoom controls, scrollbars). You must implement these controls yourself.</p>
</li>
<li><p><strong>Extra setup for some features</strong>: Enabling text layer, annotations, or non-Latin font rendering requires additional configuration.</p>
</li>
<li><p><strong>Smaller community</strong>: Issue resolution may be slower, with fewer active contributors.</p>
</li>
</ul>
<hr />
<h2 id="heading-method-4-vue-pdf-viewer">Method 4: Vue PDF Viewer</h2>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8yl6frjpsg2eers49rez.png" alt="Screenshot of Vue PDF Viewer" class="image--center mx-auto" /></p>
<p>The <a target="_blank" href="https://www.vue-pdf-viewer.dev/?utm_source=blog&amp;utm_content=building-a-pdf-viewer-in-nuxt-with-pdfjs-vue-pdf-embed-vue-pdf-and-vue-pdf-viewer"><strong>Vue PDF Viewer</strong></a> library offers a comprehensive PDF viewer component for Vue or Nuxt applications. Built on top of Mozilla’s PDF.js engine, it provides a full-featured UI experience that closely resembles popular desktop PDF viewers.</p>
<p>To add Vue PDF Viewer to your Nuxt app:</p>
<ol>
<li><p>Install <code>@vue-pdf-viewer/viewer</code> and its peer dependency pdfjs-dist via npm or yarn.</p>
</li>
<li><p>Import and register the component in your Nuxt app.</p>
</li>
<li><p>Use the component in your template and <a target="_blank" href="https://docs.vue-pdf-viewer.dev/introduction/basic-usage.html#handling-source-of-pdf-file?utm_source=blog&amp;utm_content=building-a-pdf-viewer-in-nuxt-with-pdfjs-vue-pdf-embed-vue-pdf-and-vue-pdf-viewer">set the PDF file URL</a> or path via the <code>src</code> prop.</p>
</li>
</ol>
<p>Here is the <a target="_blank" href="https://stackblitz.com/edit/nuxt-starter-pfxwrrfx?file=app.vue">link</a> to the code sample.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v5aiwxaper0kk0abk70s.gif" alt="Vue PDF Viewer demo for Nuxt" class="image--center mx-auto" /></p>
<h3 id="heading-pros-3">Pros</h3>
<ul>
<li><p><strong>Quick and easy setup</strong>: Install and render a fully working PDF viewer in just a few lines. Or use a ready-to-use setup from sample projects.</p>
</li>
<li><p><strong>Built-in toolbar</strong>: Comes with a fully functional toolbar with essential functions like page navigation, zoom, thumbnails, sidebar, text search and etc.</p>
</li>
<li><p><strong>Feature-rich PDF Viewer</strong>: Over 20+ standard features out-of-the-box, such as search, theme, print, download, rotate and etc.</p>
</li>
<li><p><strong>Highly customizable</strong>: Customize your Nuxt PDF Viewer to your own brand or build your own toolbar with Exposed APIs for search, highlight, print, rotate functions and more.</p>
</li>
<li><p><strong>Clear documentation</strong>: Well-written guides, tutorials, and examples help speed development.</p>
</li>
<li><p><strong>Actively maintained</strong>: Frequent updates, prompt bug fixes, and responsive support.</p>
</li>
</ul>
<h3 id="heading-cons-3">Cons</h3>
<ul>
<li><p><strong>Paid</strong>: Although you can try it free with watermark or through a free trial, a paid license is required to use in your Nuxt apps. Though, personally, the pricing plans are reasonable.</p>
</li>
<li><p><strong>No SSR (Server-Side Rendering) support</strong>: Depends on browser-specific APIs and cannot be rendered on the server (e.g. in Nuxt or other SSR setups).</p>
</li>
<li><p><strong>Larger bundle size</strong>: It includes full viewer UI components and assets, which is heavier as compared to smaller PDF viewer alternatives.</p>
</li>
</ul>
<hr />
<h2 id="heading-conclusion">Conclusion</h2>
<p>There’s no one-size-fits-all solution when it comes to rendering PDFs in a Nuxt application. Depending on your project’s needs, technical complexity, and user experience goals, each method covered brings something different to the table:</p>
<ul>
<li><p>Use PDF.js when you want absolute control and don’t mind investing in custom UI and handling complexity.</p>
</li>
<li><p>Choose vue‑pdf‑embed if you simply need a lightweight and easy-to-use viewer.</p>
</li>
<li><p>Go with <code>@tato30/vue‑pdf</code> for a balanced option between functionality and simplicity.</p>
</li>
<li><p>Try Vue PDF Viewer <a target="_blank" href="https://docs.vue-pdf-viewer.dev/introduction/getting-started.html#installation?utm_source=blog&amp;utm_content=building-a-pdf-viewer-in-nuxt-with-pdfjs-vue-pdf-embed-vue-pdf-and-vue-pdf-viewer">@vue‑pdf‑viewer/viewer</a> if your app requires a feature-rich solution built specifically for Vue or Nuxt, perfect for production-grade apps that need advanced functionality like search, theming, localization, and more.</p>
</li>
</ul>
<p>Thanks again for reading! I hope this guide gave you a clearer picture of what fits your Nuxt project best. Feel free to leave your thoughts or questions in the comments, I’d love to hear what you’re building! 🙏</p>
<p><img src="https://media0.giphy.com/media/v1.Y2lkPTc5MGI3NjExMzM5ODkxaWh3aHk1em5xcDg1NmczNGJ1N2J0YjRxemc1MGE1ODNtaSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/wHc92cHADhpLi/giphy.gif" alt="Gif of cat" class="image--center mx-auto" /></p>
]]></content:encoded></item><item><title><![CDATA[🔥 3 Common Problems When Building a PDF Viewer in Vue.js (And How to Actually Fix Them)]]></title><description><![CDATA[Building a PDF Viewer in Vue.js sounds simple—until you try integrating one into a real-world project. Based on my experience, when deciding whether to build or choose a PDF Viewer, there are 3 fundam]]></description><link>https://blog.vue-pdf-viewer.dev/3-common-problems-when-building-a-pdf-viewer-in-vuejs-and-how-to-actually-fix-them</link><guid isPermaLink="true">https://blog.vue-pdf-viewer.dev/3-common-problems-when-building-a-pdf-viewer-in-vuejs-and-how-to-actually-fix-them</guid><category><![CDATA[Vue.js]]></category><category><![CDATA[pdfjs-dist]]></category><category><![CDATA[pdf viewer]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[TypeScript]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[Frontend Development]]></category><dc:creator><![CDATA[Anson Chieng]]></dc:creator><pubDate>Tue, 03 Jun 2025 13:07:30 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1747453386797/e085de10-4bf8-4066-8866-7ce11d660300.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Building a PDF Viewer in Vue.js sounds simple—until you try integrating one into a real-world project. Based on my experience, when deciding whether to build or choose a PDF Viewer, there are 3 fundamentals to consider:</p>
<ol>
<li><p><strong>PDF Viewing</strong>: Loading PDF files of various types and sizes should be smooth.</p>
</li>
<li><p><strong>Default Toolbar</strong>: Basic functions such as search, zoom, page navigation and download should be readily available</p>
</li>
<li><p><strong>Print Preview</strong>: Depending on where the viewer is rendered, print results may not work as expected.</p>
</li>
</ol>
<p>Although there are a few open-source libraries PDF Viewer for Vue like <code>@tato30/vue-pdf</code> or <code>vue-pdf-embed</code>, unless you are looking for a simple PDF renderer, these solutions may not be sufficient.</p>
<p>👉 Want a Vue-first, production-ready PDF viewer? <a href="https://www.vue-pdf-viewer.dev/?utm_source=blog&amp;utm_medium=article&amp;utm_campaign=3-common-problems-when-building-a-pdf-viewer-in-vuejs-and-how-to-actually-fix-them">Try Vue PDF Viewer</a> and skip the duct tape.</p>
<p>Let’s walk through the three biggest problems I’ve seen when building Vue PDF viewers, starting with the one that kills performance: <strong>virtual scroll</strong>.</p>
<img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7ioku6i2jx8pg7jvmsm8.webp" alt="Dog running gif" style="display:block;margin:0 auto" />

<hr />
<h2>The Challenge of Smooth PDF Rendering: Virtual Scroll in Vue.js Projects</h2>
<p>Ever tried scrolling through a dense PDF—hundreds of pages deep—and felt your Vue.js app just stutter to a halt? You’re not alone. Virtual scroll is supposed to be the silver bullet, loading only the pages on-screen while the rest chill in the background. But with PDFs, it’s rarely that simple.</p>
<p>Let’s break down why virtual scroll can be such a pain in Vue projects, what usually goes wrong, and why most open-source solutions struggle to keep up.</p>
<h3>Why Virtual Scroll is Harder Than It Looks</h3>
<p>Implementing virtual scroll for a basic data table is one thing. PDFs bring their own flavor of chaos:</p>
<ul>
<li><p><strong>Rendering is resource-heavy:</strong> Each page is basically a mini-canvas. Scroll quickly, and you’re hit with a flood of draw calls.</p>
</li>
<li><p><strong>State management is complex:</strong> Tracking which pages are visible, cached, or ready to be released isn’t as straightforward as with a static list.</p>
</li>
<li><p><strong>UI jank:</strong> Jumping to a deep page? Expect scroll position jumps or content flashes.</p>
</li>
<li><p><strong>Memory leaks:</strong> Stale canvas elements often stick around, especially if you're scrolling like it's a speedrun.</p>
</li>
</ul>
<img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3ike5xs2z03wls6dmrym.webp" alt="Loading forever gif" style="display:block;margin:0 auto" />

<p>And yes, libraries like <code>@tato30/vue-pdf</code> or <code>vue-pdf-embed</code> can help for smaller files, but they weren’t built with high-performance virtual scroll in mind. Push them hard, and you’ll still hit lag, jank, or blank pages.</p>
<h3>What Smooth Virtual Scroll Actually Looks Like?</h3>
<p>The gold standard: only the visible pages and a tiny buffer are rendered. As you scroll, new pages appear instantly, and old ones quietly vanish from memory. That's easy with image galleries—but with PDFs? It’s a juggling act. Interactivity, links, and dynamic layers all add a whole new level of complexity.</p>
<p>A truly modern Vue PDF Viewer nails this by:</p>
<ul>
<li><p>Preload just enough pages (not too many!) for fluid scrolling.</p>
</li>
<li><p>Cache intelligently, releasing canvases when memory spikes.</p>
</li>
<li><p>React to zoom, theme changes, or annotations without full re-renders.</p>
</li>
</ul>
<p>💡 If you want to see this in action, getting started with <a href="https://docs.vue-pdf-viewer.dev/introduction/basic-usage.html?utm_source=blog&amp;utm_medium=article&amp;utm_campaign=virtual_scroll_pdf_vue">Vue PDF Viewer’s basic usage</a> will show you exactly how it handles virtual scroll in a real Vue setup without the usual headaches.</p>
<hr />
<h2>Building a PDF Viewer Toolbar: Out-of-the-Box and Customization Needs</h2>
<p>Here’s the deal: everyone loves a slick PDF Viewer—until they have to deal with the toolbar. You either get no toolbar or one with just the basic buttons like next page, previous page and maybe a zoom option. But when your Vue.js app needs a viewer that feels native, the toolbar goes from “nice bonus” to “can’t ship without it.”</p>
<h3>What an Out-of-the-Box Toolbar Should Include</h3>
<img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/304npsn72jix8lwb3feb.png" alt="Vue PDF Viewer with Toolbar" />

<p>Let’s keep it blunt: any PDF viewer worth using should offer these built-in essentials:</p>
<ul>
<li><p><strong>Navigation controls</strong> (prev/next, go to first/last page)</p>
</li>
<li><p><strong>Zoom options (zoom in/out, fit to width)</strong></p>
</li>
<li><p><strong>Search functionality</strong></p>
</li>
<li><p><strong>Print support</strong></p>
</li>
<li><p><strong>Download functionality</strong></p>
</li>
</ul>
<p>Once you've built these functions into your toolbar, you still need to be concerned about <strong>mobile responsive layout</strong>. If you go a bit deeper, what about handling <strong>pinch to zoom</strong> without zooming the whole browser?</p>
<p>Toolbar pain is real. If you've worked with open-source tools like <code>@tato30/vue-pdf</code> or <code>vue-pdf-embed</code>, you know exactly what I mean.</p>
<h3>Who Really Needs Toolbar Customization?</h3>
<p>If your project is anything beyond a basic MVP, you'll need toolbar customizations sooner than you think. Common requirements include:</p>
<ul>
<li><p>Matching company branding with sleek custom icons.</p>
</li>
<li><p>Hiding or showing tools based on user permissions.</p>
</li>
<li><p>Customize your toolbar by adding more features like rotate or page view modes.</p>
</li>
</ul>
<p>Customizing your PDF Viewer’s toolbar isn’t just about aesthetics; it’s about <strong>functionality</strong>, <strong>accessibility</strong>, and keeping workflows sharp and user-friendly.</p>
<p>But with most open-source libraries, it’s not so easy:</p>
<ul>
<li><p><strong>Poor documentation:</strong> Even if customization is technically possible, guides are limited. You’re often left sifting through GitHub issues for someone’s workaround.</p>
</li>
<li><p><strong>Global styles conflicts:</strong> Injecting custom buttons can break theming or hit weird CSS bugs.</p>
</li>
</ul>
<p>For apps in education, legal, or creative fields, a one-size-fits-none toolbar can break the whole product experience.</p>
<h3>How Vue PDF Viewer Makes Toolbar Customization a Breeze</h3>
<img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ydgqq5rjywf8fjaqc49n.webp" alt="Keyboard typing gif" style="display:block;margin:0 auto" />

<p>Now contrast that with a toolkit built for customization. Vue PDF Viewer puts toolbar control front and center with a slot-based toolbar system, tight icon control, and developer-friendly APIs. You can swap default icons, add new actions, and respond to toolbar events, all without wrestling the core code.</p>
<ul>
<li><p><strong>Default toolbar</strong> Functions like search, zoom, rotate, print and download can be shown or hidden easily with props.</p>
</li>
<li><p><strong>Replace default icons</strong> with your own SVGs or icons (finally, branding that fits!).</p>
</li>
<li><p><strong>Wire up your own logic</strong>—trigger downloads, emit events, track analytics.</p>
</li>
</ul>
<p>Ready to give your PDF toolbars a facelift? Dive into the step-by-step tutorial on <a href="https://docs.vue-pdf-viewer.dev/tutorial/adding-custom-icons-to-toolbar.html?utm_source=blog&amp;utm_medium=article&amp;utm_campaign=3-common-problems-when-building-a-pdf-viewer-in-vuejs-and-how-to-actually-fix-them">Adding Custom Icons to Vue PDF Toolbar</a> for a breakdown of how to use slots and Vue components to create a totally cohesive experience.</p>
<p>💡 Looking for even more ways to craft your perfect PDF Viewer and fine-tune every aspect? Skim through the official <a href="https://docs.vue-pdf-viewer.dev/customization/customize-toolbar.html?utm_source=blog&amp;utm_medium=article&amp;utm_campaign=3-common-problems-when-building-a-pdf-viewer-in-vuejs-and-how-to-actually-fix-them">Customize Vue PDF Toolbar</a> documentation for tips on changing behavior, appearance, and beyond.</p>
<p>Your team—and your users—will notice the difference.</p>
<hr />
<h2>Unreliable Print Preview: Getting it Right in Vue Projects</h2>
<p>User expectations are simple: “If I see it, I can print it. And it should look right.” Anything less? Trust evaporates.</p>
<p>Print preview probably sounds easy at first: just click the print button and send your PDF off to the printer. But if you’ve tried this in a Vue project, you might have gotten… well, some pretty unexpected results. From half-rendered pages to chopped-off toolbars making an unwanted cameo on the office laser jet, print issues have haunted developers for years.</p>
<p>The print preview struggle is real—especially when what users see in the PDF Viewer doesn't match what ends up on paper.</p>
<h3>How Traditional PDF.js Wrappers Drop the Ball</h3>
<p>You hit print, and what comes out looks nothing like what was on-screen. Here’s where things typically go wrong:</p>
<ul>
<li><p><strong>PDF rendering skips ahead</strong>: Some viewers only send the visible section of your PDF to the print dialog, cutting off the rest of the document.</p>
</li>
<li><p><strong>UI elements sneak in</strong>: Extra components (think: toolbars, overlays, side menus) end up on your printed document.</p>
</li>
<li><p><strong>Scrolling glitches</strong>: Long PDFs may print blank or half-filled pages if virtual scroll isn’t handled correctly.</p>
</li>
<li><p><strong>Dialogs make things worse</strong>: Trying to print from a modal? Sometimes you’re lucky if it prints anything at all.</p>
</li>
</ul>
<p>In other words, that feeling of déjà vu? You're definitely not alone. These bugs can turn an otherwise polished Vue app into a full-on “Why does Ctrl+P hate me?” moment.</p>
<h3>How Vue PDF Viewer Gets Print Preview Right</h3>
<img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/twc8sm0msejz20cq1gyy.webp" alt="Print issue gif" style="display:block;margin:0 auto" />

<p>This is where Vue PDF Viewer stands out from tools like <code>@tato30/vue-pdf</code> or <code>vue-pdf-embed</code>. It treats print preview as a first-class feature, not an afterthought.</p>
<p>No hacks, no browser voodoo. Just solid, built-in support. Here’s what Vue PDF Viewer does differently:</p>
<ul>
<li><p><strong>Isolated rendering for print</strong>: Only the PDF itself is rendered for printing. Toolbar, sidebar, and UI elements stay on-screen (where they belong). Every page is included, not just the chunks currently visible on-screen.</p>
</li>
<li><p><strong>Handles dialogs and overlays:</strong> Need to print from a modal or pop-up? No problem. Vue PDF Viewer renders a complete preview inside complex components, avoiding state bugs and z-index nightmares.</p>
</li>
<li><p><strong>Fallback strategy:</strong> If printing issues still persist, the library provides a reliable fallback solution that will always work.</p>
</li>
</ul>
<p>💡 If you want a step-by-step guide on making print preview work (spoiler: it’s less work than you think), the official <a href="https://docs.vue-pdf-viewer.dev/tutorial/displaying-print-preview-from-any-dialog.html?utm_source=blog&amp;utm_medium=article&amp;utm_campaign=3-common-problems-when-building-a-pdf-viewer-in-vuejs-and-how-to-actually-fix-them">Vue PDF Viewer print preview tutorial</a> shows exactly how to pull it off🚀</p>
<hr />
<h2>Conclusion</h2>
<p>Choosing the right PDF Viewer for your Vue.js project can feel overwhelming—but you deserve smooth sailing, not endless debugging. Virtual scroll stutter, print preview nightmares, and lifeless toolbars have long haunted dev teams building modern PDF experiences. Vue PDF Viewer turns these long-standing issues into non-issues.</p>
<p>Sure, libraries like <code>@tato30/vue-pdf</code> and <code>vue-pdf-embed</code> can get you started, but they're only as valuable as the support you get. Vue PDF Viewer stands apart by staying actively maintained and supported by a team that actually listens. Got a feature request, bug report, or need a demo? There’s responsive feedback and a growing library of docs and examples to help you move fast.</p>
<p>Want to hit the ground running? Dive into the <a href="https://docs.vue-pdf-viewer.dev/usage-guide/basic-toolbar-usage.html?utm_source=blog&amp;utm_medium=article&amp;utm_campaign=3-common-problems-when-building-a-pdf-viewer-in-vuejs-and-how-to-actually-fix-them">Vue PDF Viewer Basic Toolbar Guide</a> to set up controls that fit your style and workflow. Try Vue PDF Viewer in your next project and feel the difference—no hacks, no duct tape, just PDFs that work the way you hoped.</p>
<p>Got feedback, feature ideas, or battle stories from PDF Viewer integration? Drop them in the comments. What’s your biggest pain point? What feature would change your workflow?</p>
<p>Let’s make the Vue community awesome together. 🚀</p>
]]></content:encoded></item><item><title><![CDATA[🚀 Launch a PDF Viewer in Nuxt Using @vue-pdf-viewer [Guide for 2025] 🔥]]></title><description><![CDATA[PDF viewing is now a must-have for modern web apps, from online contracts to digital classrooms. If you’re building with Nuxt, you want tools that fit right in and work fast. That’s where @vue-pdf-vie]]></description><link>https://blog.vue-pdf-viewer.dev/launch-a-pdf-viewer-in-nuxt-using-vue-pdf-viewer-guide-for-2025</link><guid isPermaLink="true">https://blog.vue-pdf-viewer.dev/launch-a-pdf-viewer-in-nuxt-using-vue-pdf-viewer-guide-for-2025</guid><category><![CDATA[Vue.js]]></category><category><![CDATA[Nuxt]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[TypeScript]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[Frontend Development]]></category><category><![CDATA[pdf viewer]]></category><dc:creator><![CDATA[Kittisak Ma]]></dc:creator><pubDate>Tue, 06 May 2025 09:51:40 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1746525009496/0be24a73-dac3-4b9c-9564-63489d898f18.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>PDF viewing is now a must-have for modern web apps, from online contracts to digital classrooms. If you’re building with Nuxt, you want tools that fit right in and work fast. That’s where <a href="https://www.npmjs.com/package/@vue-pdf-viewer/viewer">@vue-pdf-viewer</a> shines 🌟</p>
<p><code>@vue-pdf-viewer</code> lets you open, zoom, and interact with PDFs right inside your Vue or Nuxt project. The setup is quick, with features like keyboard controls, responsive layouts, and even advanced document options ready to go. For developers and teams, it’s a straightforward, reliable way to add rich PDF support to any Nuxt-powered app.</p>
<p><em>Disclaimer: I work at Vue PDF Viewer.</em></p>
<img src="https://media2.giphy.com/media/v1.Y2lkPTc5MGI3NjExOTJ6b3hlanNpOGRlbDNsY2F6cDFnZDY5MTUxeHRldnUxOW1heTB4dSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/vKHKDIdvxvN7vTAEOM/giphy.gif" alt="" style="display:block;margin:0 auto" />

<hr />
<h2>Why Choose <code>@vue-pdf-viewer</code> for Nuxt Applications</h2>
<p>If you want smooth PDF handling in your Nuxt project, you need a component that just works. Vue PDF Viewer stands out for its balance of powerful features and simple setup. You can add the library into almost any Nuxt page or component with minimal setup. It's built for Nuxt and Vue, so you avoid heavy solutions or flaky workarounds.</p>
<h3>Key Features that Set <code>@vue-pdf-viewer</code> Apart</h3>
<p>Vue PDF Viewer offers everything most apps need right out of the box. Here’s what you get:</p>
<ul>
<li><p><strong>Smooth zoom and rotation:</strong> Users can view their PDFs up close, rotate pages, and not miss a detail.</p>
</li>
<li><p><strong>Keyboard navigation:</strong> Move through documents without leaving the keyboard.</p>
</li>
<li><p><strong>Responsive layouts:</strong> Fits devices big or small, so mobile users can scroll, zoom, and interact with ease.</p>
</li>
<li><p><strong>PDF layers support:</strong> Support for text, canvas and annotation layers.</p>
</li>
<li><p><strong>Search and text selection:</strong> Users find what they need fast, selecting and copying text directly from the PDF.</p>
</li>
<li><p><strong>Easy customization:</strong> Vue PDF Viewer's toolbar or theme can be configured easily to fit your business needs.</p>
</li>
</ul>
<p>If you want the full list, check the official documentation’s <a href="https://docs.vue-pdf-viewer.dev/?utm_source=blog&amp;utm_content=launch-a-pdf-viewer-in-nuxt-using-@vue-pdf-viewer">Feature Overview</a>. You’ll see plenty of advanced options, but the defaults work for most projects.</p>
<img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/is79td9zi36gxdjh1aq5.png" alt="Documentation Feature Overview" />

<h3>Comparing <code>@vue-pdf-viewer</code> to Other Popular Alternatives</h3>
<p>Several tools such as Apryse and Syncfusion compete in this space, but Vue PDF Viewer stands out for its simplicity and Vue-first design:</p>
<ul>
<li><p><strong>Vue-native</strong>: Compared to other PDF.js wrappers, Vue PDF Viewer is written entirely in Vue, which means fewer compatibility headaches.</p>
</li>
<li><p><strong>Lightweight footprint</strong>: It’s lighter than some heavyweight tools like Apryse or Syncfusion.</p>
</li>
<li><p><strong>Feature-rich yet accessible</strong>: While many open-source options lack advanced controls or built-in Nuxt support, Vue PDF Viewer gives you both out-of-the-box.</p>
</li>
</ul>
<h3>Where <code>@vue-pdf-viewer</code> Shines in Nuxt</h3>
<p>You’ll see it in action everywhere—from simple PDF previews to interactive AI-powered PDF tools and full-fledged document management systems. It's a great fit for projects where:</p>
<ul>
<li><p>✅ You need solid, bug-free PDF rendering.</p>
</li>
<li><p>✅ Custom UI or branding matters.</p>
</li>
<li><p>✅ Fast time-to-launch is key and the focus is on Vue or Nuxt development.</p>
</li>
</ul>
<p>The component’s flexibility lets you scale from basic views to complex document tools without starting over each time.</p>
<hr />
<h2>Setting Up Your Nuxt Project for PDF Viewing</h2>
<p>Getting your Nuxt project ready for PDF viewing starts with a solid foundation. You'll want installation to be smooth and straightforward asset handling to ensure reliable PDF rendering and easy file maintenance.</p>
<h3>Install Dependencies and Project Scaffolding</h3>
<p>Start by creating a new Nuxt application, or open your existing one.</p>
<h4>Nuxt 3 (recommended):</h4>
<ol>
<li><p>Initialize your project:</p>
<ul>
<li><p>Run <code>npx nuxi init my-nuxt-app</code> to create a basic structure.</p>
</li>
<li><p>Enter the project folder: <code>cd my-nuxt-app</code>.</p>
</li>
<li><p>Install dependencies: <code>npm install</code>.</p>
</li>
</ul>
</li>
<li><p>Add <code>@vue-pdf-viewer</code>:</p>
<ul>
<li>Install the package with <code>npm install @vue-pdf-viewer</code> or <code>yarn add @vue-pdf-viewer</code>.</li>
</ul>
</li>
</ol>
<p>Here’s a quick checklist before moving ahead:</p>
<ul>
<li><p>Vue 3</p>
</li>
<li><p>Node 16+ for Nuxt 3</p>
</li>
</ul>
<p>With your dependencies set, you’re ready to handle asset organization.</p>
<h3>Configure Static Assets for PDF Files</h3>
<p>How you store and serve your PDF files matters, especially when it comes to access speed and basic security. Nuxt 3 typically uses the <code>public</code> folder for this job, but there are a few gotchas to keep your files organized and safe.</p>
<p>In Nuxt 3, any files placed in the <code>public</code> folder are served from the root level. For example, a PDF saved as <code>public/sample.pdf</code> will be available at <code>/sample.pdf</code> in your browser.</p>
<h4>Best practices for asset management:</h4>
<ul>
<li><p>Organize your PDFs in subfolders (e.g. <code>public/pdfs/</code>) if you plan to store more than a few documents.</p>
</li>
<li><p>Keep clear, consistent filenames and avoid spaces, use dashes or underscores.</p>
</li>
<li><p>Regularly clean out unused files to keep your build lightweight.</p>
</li>
</ul>
<h4>File access security:</h4>
<p>Keep in mind that assets in <code>public</code> or <code>static</code> are publicly accessible. If you're dealing with sensitive or private PDFs, don't place them here. Instead:</p>
<ul>
<li><p>Use authentication and store the files outside <code>public</code></p>
</li>
<li><p>Serve them through a secure API or custom middleware.</p>
</li>
</ul>
<h4>Useful Resources</h4>
<ul>
<li><p>For more on how Nuxt handles public and static files, review the <a href="https://nuxt.com/docs/getting-started/assets">official assets documentation</a>.</p>
</li>
<li><p>If you want a guide to help you decide where files belong or to understand asset handling differences, check out <a href="https://masteringnuxt.com/blog/handling-assets-in-nuxt-3">this breakdown on handling assets in Nuxt 3</a>.</p>
</li>
<li><p>For quick comparisons on when to use each folder, see the Stack Overflow thread on <a href="https://stackoverflow.com/questions/48808182/nuxt-assets-and-static-folder-when-to-use-which">Nuxt assets and static folders</a>.</p>
</li>
</ul>
<p>By planning where your PDFs live from the start, you avoid confusion later on—especially as your app grows. Keep things neat and protect anything sensitive, and your PDF workflow in Nuxt will stay smooth and manageable.</p>
<h2>Integrating <code>@vue-pdf-viewer</code> in a Nuxt Component</h2>
<p>With your Nuxt app set up and PDFs organized, the next step is to actually bring your PDF viewer to life. You have a few key choices here: create a self-contained component for on-demand use, wrap the viewer in client-only rendering to avoid SSR issues, or register it globally for reuse in bigger projects.</p>
<p>Here’s a step-by-step guide to each approach so you choose the one that fits your needs best.</p>
<p>📘 Related: You can also follow the official <a href="https://docs.vue-pdf-viewer.dev/introduction/basic-usage.html#nuxt?utm_source=blog&amp;utm_content=launch-a-pdf-viewer-in-nuxt-using-@vue-pdf-viewer">Nuxt setup guide</a> in the documentation for a simpler quick-start example</p>
<h3>Creating a Reusable PDF Viewer Component</h3>
<p>To start, it’s best to build a dedicated Vue component that handles all your PDF viewing logic. This keeps your code tidy and lets you drop the viewer anywhere in your app.</p>
<p>Here’s how you can do it:</p>
<ol>
<li><p>Create a new file in your components folder. e.g. <code>PdfViewer.vue</code></p>
</li>
<li><p>Import <code>@vue-pdf-viewer/viewer</code> and define your props.</p>
</li>
<li><p>Pass in the <code>src</code> prop, which is the path to your PDF file.</p>
</li>
<li><p>Optionally, add viewer options to customize controls or appearance.</p>
</li>
</ol>
<p>Example code: <code>components/PdfViewer.vue</code></p>
<pre><code class="language-typescript">&lt;script setup&gt;
import { ref } from 'vue'
import { VPdfViewer } from '@vue-pdf-viewer/viewer'

const pdfSrc = ref('/pdfs/sample.pdf') // or use a prop for dynamic paths
&lt;/script&gt;

&lt;template&gt;
  &lt;v-pdf-viewer :src="pdfSrc" /&gt;
&lt;/template&gt;
</code></pre>
<p>This setup lets you easily update the source PDF or tweak viewer settings as needed. For more details about best practices with Vue components in Nuxt, check out the <a href="https://nuxt.com/docs/guide/directory-structure/components">Nuxt components directory guide</a>.</p>
<h3>Client-Side Only Rendering with</h3>
<p>Rendering PDF viewers on the server (SSR) can cause headaches since browser-specific APIs don’t exist during server-side rendering. Nuxt provides a simple fix with <code>&lt;ClientOnly&gt;</code> component in Nuxt 3.</p>
<h4>How to use it:</h4>
<p>In <strong>Nuxt 3</strong>, Wrap your PDF viewer like this:</p>
<pre><code class="language-typescript">&lt;script setup&gt;
import PdfViewer from './components/PdfViewer.vue'
&lt;/script&gt;
&lt;template&gt;
 &lt;ClientOnly&gt;
  &lt;PdfViewer /&gt;
 &lt;/ClientOnly&gt;
&lt;/template&gt;
</code></pre>
<h4>What does this do?</h4>
<p><code>&lt;ClientOnly&gt;</code> tells Nuxt to delay rendering of your PDF viewer component until it's running in the browser. This prevents SSR-related errors from happening when browser-only code is accessed too early.</p>
<p>If you need a deeper explanation or run into issues, check out <a href="https://stackoverflow.com/questions/72367724/client-only-nuxt-3-vue-plugin">this discussion on Nuxt client-only plugins</a>.</p>
<h3>Using Nuxt Plugins for Global Registration</h3>
<p>If your app needs to display PDFs in many places, it helps to register the viewer as a global component. Nuxt’s plugin system makes this smooth and keeps your code DRY (don’t repeat yourself).</p>
<p>Here’s the approach:</p>
<ol>
<li><p>Create a new plugin file in <code>plugins/vue-pdf-viewer.js</code> (or <code>.ts</code>).</p>
</li>
<li><p>Import and register <code>@vue-pdf-viewer</code> globally.</p>
</li>
<li><p>In your Nuxt config, make sure the plugin is loaded only on the client.</p>
</li>
</ol>
<p>Example for Nuxt 3:</p>
<pre><code class="language-js">// plugins/vue-pdf-viewer.client.js
import { defineNuxtPlugin } from '#app'
import { VPdfViewer } from '@vue-pdf-viewer/viewer'

export default defineNuxtPlugin((nuxtApp) =&gt; {
  nuxtApp.vueApp.component('VPdfViewer', VPdfViewer)
})
</code></pre>
<p>Nuxt automatically reads the files in the <code>plugins/</code> directory and loads them at the creation of the Vue application. For full details, visit the <a href="https://nuxt.com/docs/guide/directory-structure/plugins">Nuxt plugins directory documentation</a>.</p>
<p>With the viewer globally registered, you can use <code>&lt;VPdfViewer /&gt;</code> anywhere in your project—no manual imports needed. This approach saves you from repetitive imports and keeps your codebase neat as your app scales.</p>
<hr />
<h2>Bonus Section: Styling Your PDF Viewer</h2>
<p>Nobody wants a PDF viewer that looks out of place or breaks your app’s design flow. With a little effort, you can easily style <code>@vue-pdf-viewer</code> to match your branding.</p>
<p><strong>Tips for styling:</strong></p>
<ul>
<li><p><strong>Use CSS for visual tweaks:</strong> Adjust background colors, spacing, and toolbar icons by targeting the viewer’s CSS classes. For detailed steps and best practices, check out this resource on <a href="https://docs.vue-pdf-viewer.dev/customization/adjust-styles.html?utm_source=blog&amp;utm_content=launch-a-pdf-viewer-in-nuxt-using-@vue-pdf-viewer">customizing CSS in PDF viewers</a>.</p>
</li>
<li><p><strong>Use Slots for custom controls:</strong> Vue’s slot system makes it easy to insert your own buttons or menus on the toolbar or sidebar.</p>
</li>
<li><p><strong>Hide or reorder UI parts:</strong> Vue PDF Viewer toolbar can be toggled or reorganized through props or CSS. Keep only what you need on the screen.</p>
</li>
</ul>
<hr />
<h2>Conclusion</h2>
<img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dlrpafnax7k26xnylsra.png" alt="Vue PDF Viewer" />

<p>Launching a PDF viewer in Nuxt with <a href="https://www.vue-pdf-viewer.dev/?utm_source=blog&amp;utm_content=launch-a-pdf-viewer-in-nuxt-using-@vue-pdf-viewer">Vue PDF Viewer</a> is fast and hassle-free. You get powerful display options, modern controls, and responsive layouts—ready to go with just a few steps. The component’s flexibility means you can start simple or customize for a tailored user experience.</p>
<p>🙏 Thanks for reading—if you’ve tried this in your own Nuxt app, please feel to share what you built or what you want to see next in Vue PDF Viewer.</p>
<p>I'm looking forward to seeing what you build with <a href="https://www.vue-pdf-viewer.dev/?utm_source=blog&amp;utm_content=launch-a-pdf-viewer-in-nuxt-using-@vue-pdf-viewer">Vue PDF Viewer</a> 🚀</p>
<img src="https://media4.giphy.com/media/v1.Y2lkPTc5MGI3NjExbzZ4MXB3cnNsam9uNTFtZHFvN24wMjYweTBxMmw0bHB2Z2FkazkyYyZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/a3IWyhkEC0p32/giphy.gif" alt="" style="display:block;margin:0 auto" />]]></content:encoded></item><item><title><![CDATA[What are PDF.js Layers and How You Can Use them in Vue.js]]></title><description><![CDATA[PDF is everywhere, no matter what kind of web app you’re building, you’re bound to need a convenient PDF viewer at some point. But if you’ve ever tried to handle PDFs on the web, you know it can feel like wrestling with outdated plugins, iframe worka...]]></description><link>https://blog.vue-pdf-viewer.dev/what-are-pdfjs-layers-and-how-you-can-use-them-in-vuejs</link><guid isPermaLink="true">https://blog.vue-pdf-viewer.dev/what-are-pdfjs-layers-and-how-you-can-use-them-in-vuejs</guid><category><![CDATA[Vue.js]]></category><category><![CDATA[pdfjs-dist]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[TypeScript]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[Frontend Development]]></category><category><![CDATA[pdf viewer]]></category><category><![CDATA[Nuxt]]></category><dc:creator><![CDATA[Kittisak Ma]]></dc:creator><pubDate>Tue, 04 Mar 2025 06:56:37 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1740629825185/75af6363-e0da-4c21-bc54-d560ce140779.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>PDF is everywhere, no matter what kind of web app you’re building, you’re bound to need a convenient PDF viewer at some point. But if you’ve ever tried to handle PDFs on the web, you know it can feel like wrestling with outdated plugins, iframe workaround or settling for awkward pop-ups.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExZXJscm9zemUwdXlqb3N4bzdxc3Z5MDBzemZqZjdob2pzdDYybWI2YiZlcD12MV9naWZzX3NlYXJjaCZjdD1n/p8CIVScK4TqUI2aBdA/giphy.gif">https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExZXJscm9zemUwdXlqb3N4bzdxc3Z5MDBzemZqZjdob2pzdDYybWI2YiZlcD12MV9naWZzX3NlYXJjaCZjdD1n/p8CIVScK4TqUI2aBdA/giphy.gif</a></div>
<p> </p>
<p>That’s where PDF.js comes in—it's an open-source JavaScript library for rendering PDFs right in your browser. Now, if you’re like me and build apps in Vue.js, figuring out how to use PDF.js in your project can be tricky at first.</p>
<p>To leverage PDF.js's capabilities, it's important to understand its layered architecture. If you’ve ever wondered, “How do I enable text selection?” or “How do I handle links inside the PDF?” or even “How do I build advanced features like annotations?”, the answer usually lies in understanding these layers.</p>
<p>In this article, I’ll show you how PDF.js creates layers, what each layer is responsible for, and how you can apply them to your next Vue project. Let’s get going!</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExZG15dXkxZXZqNmVsYWFjcGlyaGJteG03dnVtbm45anAzZTg2Zm84eSZlcD12MV9naWZzX3NlYXJjaCZjdD1n/TRFcNpyLTdo2kUmkwm/giphy.gif">https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExZG15dXkxZXZqNmVsYWFjcGlyaGJteG03dnVtbm45anAzZTg2Zm84eSZlcD12MV9naWZzX3NlYXJjaCZjdD1n/TRFcNpyLTdo2kUmkwm/giphy.gif</a></div>
<p> </p>
<hr />
<h2 id="heading-vue-pdf-viewer-flexible-and-powerful-vuejs-pdf-component">Vue PDF Viewer: Flexible and Powerful Vue.js PDF Component</h2>
<p>Quick heads up on something I’ve been working on: <a target="_blank" href="https://www.vue-pdf-viewer.dev/?utm_source=blog&amp;utm_content=how-pdfjs-creates-layers-and-what-each-layer-is-for">Vue PDF Viewer</a>, a handy PDF Viewer that renders PDFs right within your Vue or Nuxt app. It packs over 20 features, including out-of-the-box default toolbar, customization and responsive design, so your users never have to leave your site to interact with your documents.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4mej2yw6utliflphjc4j.png" alt="Vue PDF Viewer" /></p>
<p>If that sounds interesting, I’d love for you to give <a target="_blank" href="https://www.vue-pdf-viewer.dev/?utm_source=blog&amp;utm_content=how-pdfjs-creates-layers-and-what-each-layer-is-for">Vue PDF Viewer</a> a try. Your support helps me keep creating awesome tools and tutorials like this one. ❤️</p>
<hr />
<h2 id="heading-overview-of-pdfjs-layers">Overview of PDF.js Layers</h2>
<p>Before we dive in deep, here’s a quick snapshot of the four major layers in PDF.js. Each layer handles a specific aspect of rendering or user interaction:</p>
<ol>
<li><p><strong>Canvas Layer</strong>: Renders the static visual content of your PDF (shapes, images, text-as-graphics). It is the foundation of the PDF Viewer.</p>
</li>
<li><p><strong>Text Layer</strong>: Sits on top of the canvas to ensure that text is selectable and searchable.</p>
</li>
<li><p><strong>Annotation Layer</strong>: Handles interactive elements (links, forms, highlights) so users can click, type, or navigate.</p>
</li>
<li><p><strong>Structural Layer</strong>: Manages the overall layout, including alignment and scaling for all the other layers.</p>
</li>
</ol>
<p>By splitting different functionalities into distinct layers, PDF.js remains modular, efficient, and surprisingly easy to tweak.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741071352186/f0ffac48-d186-45d9-848b-169450f3d923.png" alt class="image--center mx-auto" /></p>
<hr />
<p>Let’s start by creating a fresh Vue.js project to integrate PDF.js.</p>
<h2 id="heading-set-up-vuejs-project">Set up Vue.js Project</h2>
<p>In this article, I used Codepen as a code editor. If you want to follow along, you can create a new <code>Pen</code> on Codepen and follow the steps below.</p>
<h3 id="heading-step-1-pick-a-vue-pen-template">Step 1. Pick a Vue Pen Template</h3>
<p>The easiest way to get started is by using CodePen’s built-in Vue template. From the left menu, click on the <code>Pen</code> menu to open the options, then pick <code>Vue Pen</code>.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/arjjfxblv9ji5o9g5lo7.png" alt="Codepen - Vue Pen" /></p>
<p>This gives you a preconfigured environment with a default Vue setup. In this interface, you can experiment with Vue code and instantly see your results in the preview area.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gja38jkd6ldarx87hpc6.png" alt="Codepen - first impression of Vue code editor" /></p>
<h3 id="heading-step-2-configure-the-project-and-install-pdfjs">Step 2. Configure the project and install PDF.js</h3>
<p>Next, let’s configure our Vue project to use the <code>pdfjs-dist</code> library.</p>
<ol>
<li><p><strong>Open Settings</strong>: Click on the Settings button at the top of your Pen.</p>
</li>
<li><p><strong>Select JS Options</strong>: In the popup, switch to the JS tab.</p>
</li>
<li><p><strong>Pick Vue Version</strong>: Under Vue version, select Vue 3 (or whichever version fits your needs).</p>
</li>
<li><p><strong>Add Packages</strong>: In the Add Packages box, search for and add <code>pdfjs-dist</code>.</p>
</li>
<li><p><strong>Save and Close</strong>: Click Save &amp; Close to apply your changes.</p>
</li>
</ol>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ydastf7pmpyaf5z0z5g8.png" alt="Codepen - how to set Vue version and install dependencies" /></p>
<p>CodePen will automatically inject an import statement for <code>pdfjs-dist</code> into your code. You’ll typically want to move that statement below your <code>&lt;script&gt;</code> section to keep things clean and organized.</p>
<p>That’s it! You’re now set up to start experimenting with PDF.js layers within a Vue environment. So let us get to the layers.</p>
<hr />
<h2 id="heading-1-canvas-layer">1. Canvas Layer</h2>
<h3 id="heading-purpose">Purpose</h3>
<p>The <strong>Canvas Layer</strong> is the foundation—it’s where PDF.js draws the visual elements such as images, shapes, and text (as graphics). Essentially, what you see on-screen is coming from this layer.</p>
<h3 id="heading-how-it-works">How It Works</h3>
<ul>
<li><p>PDF.js uses the HTML <code>&lt;canvas&gt;</code> element to display the PDF's visual content</p>
</li>
<li><p>It utilizes the browser's <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D">2D canvas API</a> for high-performance rendering.</p>
</li>
<li><p>This means your PDF content will look consistent and accurate across various screen sizes and devices.</p>
</li>
</ul>
<h3 id="heading-use-cases">Use Cases</h3>
<ul>
<li><p>Ideal for <strong>non-interactive</strong> or <strong>static</strong> PDF content.</p>
</li>
<li><p>It renders the document as an image, ensuring PDF’s fonts, colors, and layouts are consistent across all devices.</p>
</li>
</ul>
<h3 id="heading-example-of-canvas-layer-code-with-vue">Example of Canvas layer Code with Vue</h3>
<p>Here’s a quick CodePen demo showcasing a minimal Canvas Layer setup in Vue.js.</p>
<p>{% codepen https://codepen.io/9haroon/pen/vEBVBqR %}</p>
<h3 id="heading-how-the-code-works">📜 How the Code Works</h3>
<p>Below, I’ll walk through the major steps for rendering a PDF page onto the canvas.</p>
<h4 id="heading-1-setting-up-the-pdf-worker">(1) Setting Up the PDF Worker</h4>
<p>Before loading the PDF, we need to configure the <strong>PDF worker</strong>. The worker is responsible for processing the PDF in a separate thread, improving performance.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> PDFJS <span class="hljs-keyword">from</span> <span class="hljs-string">"https://esm.sh/pdfjs-dist"</span>;
<span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> PDFWorker <span class="hljs-keyword">from</span> <span class="hljs-string">"https://esm.sh/pdfjs-dist/build/pdf.worker.min"</span>;

<span class="hljs-keyword">try</span> {
  PDFJS.GlobalWorkerOptions.workerSrc = PDFWorker;
} <span class="hljs-keyword">catch</span> (e) {
  <span class="hljs-built_in">window</span>.pdfjsWorker = PDFWorker;
}
</code></pre>
<p><strong>Explanation:</strong></p>
<ul>
<li><p>Here, we import <code>pdf.worker.min.js</code> and set it as the worker source.</p>
</li>
<li><p>The worker processes the PDF in a separate thread so our UI is not blocked.</p>
</li>
<li><p>If an error occurs, the worker is assigned to <code>window.pdfjsWorker</code> as a fallback</p>
</li>
</ul>
<h4 id="heading-2-fetching-and-loading-the-pdf">(2) Fetching and Loading the PDF</h4>
<pre><code class="lang-js"> <span class="hljs-keyword">const</span> PDF_SRC = <span class="hljs-string">"https://pdfobject.com/pdf/pdf_open_parameters_acro8.pdf"</span>;
 <span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  ...
  methods: {
    processLoadingTask(source) {
      <span class="hljs-keyword">const</span> loadingTask = PDFJS.getDocument(source);
      loadingTask.promise
      .then(<span class="hljs-function"><span class="hljs-params">docProxy</span> =&gt;</span> ...)
      .then(<span class="hljs-function"><span class="hljs-params">page</span> =&gt;</span> {
         ...
         const renderContext = {
           <span class="hljs-attr">canvasContext</span>: context,
           <span class="hljs-attr">viewport</span>: viewport
         };
         <span class="hljs-keyword">return</span> page.render(renderContext);
      })
    }
   },
   <span class="hljs-comment">// Start the process when the component is mounted</span>
   mounted() {
    <span class="hljs-built_in">this</span>.processLoadingTask(PDF_SRC);
   }
 }
</code></pre>
<p><strong>Explanation:</strong></p>
<ul>
<li><p>The <code>processLoadingTask</code> method initializes PDF loading via <code>PDFJS.getDocument(source)</code> from pdfjs-dist.</p>
</li>
<li><p>Once the PDF is fetched (from <code>PDF_SRC</code>), we store the document proxy (<code>docProxy</code>).</p>
</li>
<li><p>The total number of pages is determined and stored in <code>totalPages</code>.</p>
</li>
</ul>
<h4 id="heading-3-rendering-the-canvas-layer">(3) Rendering the Canvas Layer</h4>
<p><strong>Explanation:</strong> After the PDF is loaded and we have a page object, the first page is extracted using <code>getPage(1)</code>. PDF.js then:</p>
<ul>
<li><p>Scales the canvas to match the PDF page dimensions.</p>
</li>
<li><p>A <code>&lt;canvas&gt;</code> element (<code>canvasLayer</code>) is used to render the PDF page as an image.</p>
</li>
<li><p>The rendering process is handled by <code>page.render(renderContext)</code>, where <code>canvasContext</code> paints the page content onto the canvas.</p>
</li>
</ul>
<p>This ensures the final output accurately matches the original PDF’s appearance.</p>
<hr />
<h2 id="heading-2-text-layer">2. Text Layer</h2>
<h3 id="heading-purpose-1">Purpose</h3>
<p>The <strong>Text Layer</strong> ensures that the text in your PDF is <strong>selectable, searchable, and accessible</strong>. While the Canvas Layer does the heavy lifting of rendering visuals, the Text Layer is what lets you highlight and copy actual text.</p>
<h3 id="heading-how-it-works-1">How It Works</h3>
<ul>
<li><p>PDF.js extracts the <strong>text content</strong> separately from the PDF.</p>
</li>
<li><p>It positions each piece of text exactly over the underlying canvas, using absolutely positioned <code>&lt;div&gt;</code> elements.</p>
</li>
<li><p>Even though you might not see these text <code>&lt;div&gt;</code> visually (they’re often transparent), they’re there to support <strong>selection</strong> and <strong>searching</strong>.</p>
</li>
</ul>
<h3 id="heading-use-cases-1">Use Cases</h3>
<ul>
<li><p>Enable <strong>text selection</strong> and <strong>copying</strong> from the PDF.</p>
</li>
<li><p>Text layer is crucial for <strong>accessibility</strong>, as it enables screen readers to interpret the content.</p>
</li>
<li><p>Provide text searching and highlighting within the PDF viewer.</p>
</li>
<li><p>Keep the text aligned with the rendered PDF page</p>
</li>
</ul>
<h3 id="heading-text-layer-code-example">Text layer Code Example</h3>
<p>Here’s a Vue.js CodePen example that demonstrates a Text Layer in action:</p>
<p>{% codepen https://codepen.io/9haroon/pen/GgKbgmm %}</p>
<h3 id="heading-how-the-code-works-1">📜 How the Code Works</h3>
<h4 id="heading-1-structuring-the-layers">(1) Structuring the Layers</h4>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">"pdfLayersWrapper"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"pdf__layers"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"pdf__canvas-layer"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">canvas</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">"canvasLayer"</span> /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">"textLayer"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"pdf__text-layer"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p><strong>Explanation:</strong></p>
<ul>
<li><p>The <code>pdfLayersWrapper</code> is a container that holds both the <strong>Canvas Layer</strong> and the <strong>Text Layer</strong>.</p>
</li>
<li><p>The <strong>Canvas Layer</strong> (<code>canvasLayer</code>) displays the PDF page visually.</p>
</li>
<li><p>The <strong>Text Layer</strong> (<code>textLayer</code>) sits on top of the canvas, allowing text selection.</p>
</li>
</ul>
<h4 id="heading-2-fetching-and-loading-the-pdf-1">(2) Fetching and Loading the PDF</h4>
<p>(Identical to the steps in the <strong>Canvas Layer</strong>—we load the PDF document first.)</p>
<h4 id="heading-3-rendering-the-text-layer">(3) Rendering the Text Layer</h4>
<pre><code class="lang-js">renderText(pdfPageProxy, textLayerContainer, viewport) {
  ...
  pdfPageProxy
    .getTextContent()
    .then(<span class="hljs-function">(<span class="hljs-params">content</span>) =&gt;</span> {
      <span class="hljs-keyword">const</span> renderTask = <span class="hljs-keyword">new</span> PDFJS.TextLayer({
        <span class="hljs-attr">container</span>: textLayerContainer,
        <span class="hljs-attr">textContentSource</span>: content,
        <span class="hljs-attr">viewport</span>: viewport.clone({ <span class="hljs-attr">dontFlip</span>: <span class="hljs-literal">true</span> })
      });
      <span class="hljs-keyword">return</span> renderTask.render();
    });
 },
 processLoadingTask (source) {
  ...
  this.renderText(...)
 }
</code></pre>
<p><strong>Explanation:</strong></p>
<ul>
<li><p>Render the text layer (<code>this.renderText()</code>).</p>
</li>
<li><p><code>pdfPageProxy.getTextContent()</code> retrieves the text data from the PDF page.</p>
</li>
<li><p>This data is passed into a new <code>TextLayer</code>, specifying:</p>
<ul>
<li><p><code>container</code>: Container where text is rendered.</p>
</li>
<li><p><code>textContentSource</code>: Extracted text data from the PDF.</p>
</li>
<li><p><code>viewport</code>: Defines text positioning and scaling.</p>
</li>
</ul>
</li>
<li><p><code>renderTask.render()</code> places invisible but selectable text <code>&lt;div&gt;</code> over the canvas.</p>
</li>
</ul>
<hr />
<h2 id="heading-3-annotation-layer">3. Annotation Layer</h2>
<h3 id="heading-purpose-2">Purpose</h3>
<p>The <strong>Annotation Layer</strong> handles <strong>interactive elements</strong> like hyperlinks, highlights, form fields, and comments. If you need your PDF viewer to support internal linking (jumping to different pages), or if your PDFs have fillable forms, this layer is for you.</p>
<h3 id="heading-how-it-works-2">How It Works</h3>
<ul>
<li><p>PDF.js extracts annotation data (links, form fields, etc.) from the PDF.</p>
</li>
<li><p>It overlays these data as <strong>interactive HTML elements</strong> (e.g. <code>&lt;a&gt;</code>, <code>&lt;input&gt;</code>, <code>&lt;textarea&gt;</code>), which sit above the <strong>Canvas Layer</strong> and <strong>Text Layer</strong> positioned using CSS.</p>
</li>
<li><p>This layer ensures that users can click, type, and interact without altering the PDF’s static visuals.</p>
</li>
</ul>
<h3 id="heading-use-cases-2">Use Cases</h3>
<ul>
<li><p>Clicking on links within PDF to navigate between pages.</p>
</li>
<li><p>Rendering highlights, underlines, and notes from PDF annotations.</p>
</li>
<li><p>Displaying interactive form fields within a PDF.</p>
</li>
</ul>
<h3 id="heading-annotation-layer-code-example">Annotation layer Code Example</h3>
<p>Check out this CodePen example on the <strong>Annotation Layer</strong> for Vue.js:</p>
<p><em>You can click the links inside the Codepen to change the PDF's page.</em></p>
<p>{% codepen https://codepen.io/9haroon/pen/qEWzOzz %}</p>
<h3 id="heading-how-the-code-works-2">📜 How the Code Works</h3>
<h4 id="heading-1-structuring-the-layers-1">(1) Structuring the Layers</h4>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">"pdfLayersWrapper"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"pdf__layers"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"pdf__canvas-layer"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">canvas</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">"canvasLayer"</span> /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">"textLayer"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"pdf__text-layer"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">"annotationLayer"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"pdf__annotation-layer"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p><strong>Explanation:</strong></p>
<ul>
<li><p>We add another <code>&lt;div&gt;</code> for the <strong>Annotation Layer</strong> within <code>pdfLayersWrapper</code>.</p>
</li>
<li><p>The <strong>Annotation Layer</strong> is positioned on top of the <strong>Canvas Layer</strong> and <strong>Text Layer</strong>.</p>
</li>
</ul>
<h4 id="heading-2-fetching-and-loading-the-pdf-2">(2) Fetching and Loading the PDF</h4>
<p>(Again, the same initial PDF loading steps as before.)</p>
<h4 id="heading-3-rendering-the-annotation-layer">(3) Rendering the Annotation Layer</h4>
<pre><code class="lang-js"> <span class="hljs-keyword">async</span> getAnnotations(pageProxy) {
  <span class="hljs-keyword">const</span> annotations = <span class="hljs-keyword">await</span> pageProxy.getAnnotations({ <span class="hljs-attr">intent</span>: <span class="hljs-string">"display"</span> });
  <span class="hljs-keyword">return</span> annotations;
 },
 <span class="hljs-keyword">async</span> renderAnnotations(pdfPageProxy, annotationLayerContainer, viewport) {
   <span class="hljs-keyword">const</span> annotations = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.getAnnotations(pdfPageProxy);
   ...
   const annotationLayer = <span class="hljs-keyword">new</span> PDFJS.AnnotationLayer({
    <span class="hljs-attr">div</span>: annotationLayerContainer,
    <span class="hljs-attr">viewport</span>: clonedViewport,
    <span class="hljs-attr">page</span>: pdfPageProxy
  });
  <span class="hljs-keyword">await</span> annotationLayer.render({
    ...,
    annotations,
    <span class="hljs-attr">linkService</span>: <span class="hljs-keyword">new</span> SimpleLinkService(),
    ...
  })
 }
</code></pre>
<p><strong>Explanation:</strong></p>
<ul>
<li><p><code>getAnnotations</code> retrieves all annotation info from the PDF page (links, form fields, etc.).</p>
</li>
<li><p>We clone the viewport to match the page’s dimensions for correct positioning.</p>
</li>
<li><p><code>renderAnnotations</code> is then called to replace existing elements in <code>annotationLayerContainer</code> before rendering new ones. It does so by:</p>
<ul>
<li><p>Creating a new <code>AnnotationLayer</code> instance to manage and render annotation elements.</p>
</li>
<li><p>Displaying the annotation layer by <code>annotationLayer.render({...})</code>, passing in the annotations and <code>SimpleLinkService()</code> to handle internal PDF links.</p>
</li>
</ul>
</li>
</ul>
<h4 id="heading-4-handling-internal-link-clicks">(4) Handling Internal Link Clicks</h4>
<pre><code class="lang-js">...
annotationLayerContainer.addEventListener(<span class="hljs-string">"click"</span>, <span class="hljs-keyword">async</span> (event) =&gt; {
  ...
  const annotationLinkId = annotations.find(<span class="hljs-function">(<span class="hljs-params">ele</span>) =&gt;</span> ele.id === id);
  ...
  const pageIndex = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.pdfDocProxy.getPageIndex(
    annotationLinkId.dest[<span class="hljs-number">0</span>]
  );
  <span class="hljs-built_in">this</span>.currentPage = pageIndex + <span class="hljs-number">1</span>;
});
</code></pre>
<p><strong>Explanation:</strong></p>
<ul>
<li><p>When a user <strong>clicks on a link</strong> inside the PDF, the event checks if it's an annotation.</p>
</li>
<li><p>If it is, we look up the destination page by <code>getPageIndex()</code> and see if it points to a different page in the PDF.</p>
</li>
<li><p>We then navigate to that page by updating <code>this.currentPage</code>.</p>
</li>
</ul>
<h4 id="heading-5-handling-page-navigation">(5) Handling Page Navigation</h4>
<ul>
<li>A simple navigation bar lets users switch between pages.</li>
</ul>
<pre><code class="lang-html"> <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"page-navigation"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">:disabled</span>=<span class="hljs-string">"currentPage &lt;= 1"</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"--currentPage"</span>&gt;</span>
   <span class="hljs-symbol">&amp;larr;</span> 
  <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>{{ currentPage }}/{{ totalPages }}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">:disabled</span>=<span class="hljs-string">"currentPage &gt;= totalPages"</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"++currentPage"</span>&gt;</span>
   <span class="hljs-symbol">&amp;rarr;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
 <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p><strong>Explanation:</strong></p>
<ul>
<li><p>The <code>currentPage</code> value updates when navigation buttons are clicked.</p>
</li>
<li><p><code>watch: { currentPage(newValue) { ... } }</code> ensures that all layers are re-rendered when the page changes.</p>
</li>
<li><p>This ensures all layers—<strong>Canvas</strong>, <strong>Text</strong>, and <strong>Annotation</strong>—stay in sync.</p>
</li>
</ul>
<hr />
<h2 id="heading-4-structural-layer">4. Structural Layer</h2>
<h3 id="heading-purpose-3">Purpose</h3>
<p>Think of the <strong>Structural Layer</strong> as the master layout manager. It keeps the Canvas, Text, and Annotation layers correctly aligned, scaled, and positioned when users zoom in or out, or when the window is resized.</p>
<p>This layer is a must-have when creating a <strong>PDF viewer</strong> as it serves as the <strong>foundation</strong> that glues all other layers together.</p>
<h3 id="heading-how-it-works-3">How It Works</h3>
<ul>
<li><p>The <strong>Structural Layer</strong> is typically implemented by a container element (<code>&lt;div&gt;</code>) that wraps all other layers.</p>
</li>
<li><p>Maintains consistent positioning among layers so they don’t drift apart during zooms or scrolls.</p>
</li>
<li><p>Acts as the foundation that ties everything together, so your PDF viewer remains cohesive.</p>
</li>
</ul>
<h3 id="heading-use-cases-3">Use Cases</h3>
<ul>
<li><p>Ensure a <strong>consistent user experience</strong> across different screen sizes and resolutions.</p>
</li>
<li><p>Enable <strong>smooth zooming</strong> by scaling all layers proportionally.</p>
</li>
<li><p>Centralize navigation and layout logic (e.g. controlling how the viewer scrolls from one page to another.)</p>
</li>
</ul>
<p>In our code examples, the <code>&lt;div ref="pdfLayersWrapper" class="pdf__layers"&gt;</code> element serves as the Structural Layer, wrapping for other layers:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">"pdfLayersWrapper"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"pdf__layers"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"pdf__canvas-layer"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">canvas</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">"canvasLayer"</span> /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">"textLayer"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"pdf__text-layer"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">"annotationLayer"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"pdf__annotation-layer"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<h3 id="heading-why-is-this-important">Why is this important?</h3>
<ul>
<li><p>The <strong>Structural Layer</strong> wrapper ensures the Canvas, Text, and Annotation Layers all stay in sync, even when you zoom or flip through pages.</p>
</li>
<li><p>You can customize the wrapper to handle special behaviors like lazy-loading pages, scroll snapping and other performance optimizations.</p>
</li>
</ul>
<hr />
<h2 id="heading-how-layers-work-together">How Layers Work Together</h2>
<p>Here’s how all four layers in PDF.js work together in harmony:</p>
<ol>
<li><p><strong>Rendering Process</strong>:<br /> Each page is first drawn onto the <strong>Canvas Layer</strong> (visual content). Next, the <strong>Text Layer</strong> is layered on top to enable selection and searching. Finally, the <strong>Annotation Layer</strong> is placed at the very top, providing interactive elements like links and form fields.</p>
</li>
<li><p><strong>Interactivity</strong>:<br /> The <strong>Annotation Layer</strong> handles user events (like clicking on links or typing into form fields), while the Text Layer ensures text can be highlighted, copied, or searched.</p>
</li>
<li><p><strong>PDF Viewer</strong>:<br /> The <strong>Structural Layer</strong> wraps everything up, ensuring that zooming, resizing, and navigation across pages remain consistent. It keeps all layers aligned and responsive, so users get a polished viewing experience.</p>
</li>
</ol>
<hr />
<h2 id="heading-conclusion">Conclusion</h2>
<p>I’ve used PDF.js in a variety of Vue.js projects, from simple PDF previews to fully interactive document systems, the layered architecture is always at the core.</p>
<p><strong>Why does this matter for you?</strong></p>
<ul>
<li><p>You can optimize each layer for performance or user experience.</p>
</li>
<li><p>You can customize how your viewer handles interactions, text searches, or forms.</p>
</li>
<li><p>You’ll find it much easier to maintain or extend your PDF viewer code.</p>
</li>
</ul>
<p>By understanding these layers, you will be able to optimize PDF.js implementations, customize features, and deliver a better user experience. Whether you’re building a simple Vue.js PDF viewer or a complex document management system, leveraging these layers effectively will set your project up for success.</p>
<hr />
<h2 id="heading-vue-pdf-viewer-the-pdf-viewer-built-for-vuejs-developers">Vue PDF Viewer: The PDF Viewer Built for Vue.js Developers 🚀</h2>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4mej2yw6utliflphjc4j.png" alt="Vue PDF Viewer" /></p>
<p>If you enjoyed this article, I’d love for you to check out <a target="_blank" href="https://www.vue-pdf-viewer.dev/?utm_source=blog&amp;utm_content=how-pdfjs-creates-layers-and-what-each-layer-is-for">Vue PDF Viewer</a>. It’s a PDF Viewer built from the ground up for Vue and Nuxt applications. Whether you’re just starting out or already running a large-scale app, Vue PDF Viewer got you covered.</p>
<p>Designed with developers in mind, Vue PDF Viewer offers:</p>
<ul>
<li><p>Simple Vue integration to get you up and running fast.</p>
</li>
<li><p>Advanced customization so you can nail that perfect look and feel.</p>
</li>
<li><p>Responsive layouts that adapt to any device.</p>
</li>
<li><p>Developer-friendly APIs for more flexibility.</p>
</li>
</ul>
<p>Your support motivates me to keep creating tools and content for the Vue community. Thank you for checking out <a target="_blank" href="https://www.vue-pdf-viewer.dev/?utm_source=blog&amp;utm_content=how-pdfjs-creates-layers-and-what-each-layer-is-for">Vue PDF Viewer</a>. Happy coding! 🙏</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExM2Y2OHdzN2syZXd2ZmMxc24zdGJiM2NvZWd6enV6cHZ4bWNtejFyaCZlcD12MV9naWZzX3NlYXJjaCZjdD1n/ule4vhcY1xEKQ/giphy.gif">https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExM2Y2OHdzN2syZXd2ZmMxc24zdGJiM2NvZWd6enV6cHZ4bWNtejFyaCZlcD12MV9naWZzX3NlYXJjaCZjdD1n/ule4vhcY1xEKQ/giphy.gif</a></div>
]]></content:encoded></item><item><title><![CDATA[🌟 Vue 3 UI Libraries: 6 Most Popular Picks for 2025 🚀]]></title><description><![CDATA[Edit: Back in 2024, I shared a list of the "⚡️Top 6 Vue.js UI Libraries (Vue 3) Trending in 2024 🔥". Now in 2025 I couldn’t resist revisiting this topic to see what has changed and which libraries are still making waves 🎉
If you have been working w...]]></description><link>https://blog.vue-pdf-viewer.dev/vue-3-ui-libraries-6-most-popular-picks-for-2025</link><guid isPermaLink="true">https://blog.vue-pdf-viewer.dev/vue-3-ui-libraries-6-most-popular-picks-for-2025</guid><category><![CDATA[Vue.js]]></category><category><![CDATA[Nuxt]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[TypeScript]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[Frontend Development]]></category><dc:creator><![CDATA[Anson Chieng]]></dc:creator><pubDate>Tue, 28 Jan 2025 04:34:51 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1738038711542/851ac63f-adee-4d94-9536-3c622562875d.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>Edit: Back in 2024, I shared a list of the "</em><a target="_blank" href="https://blog.vue-pdf-viewer.dev/top-6-vuejs-ui-libraries-vue-3-trending-in-2024"><em>⚡️Top 6 Vue.js UI Libraries (Vue 3) Trending in 2024 🔥</em></a><em>". Now in 2025 I couldn’t resist revisiting this topic to see what has changed and which libraries are still making waves 🎉</em></p>
<p>If you have been working with Vue.js for a while, you will know how it hooks you with its simplicity, flexibility, and sheer performance. It has been my go-to framework for years, and I am always on the lookout for tools that make developing with Vue even better. UI component libraries are some of the best tools in that category, they save so much time and help you build beautiful, responsive interfaces without breaking a sweat.</p>
<p>Since Vue 3 officially became the default after Vue 2’s retirement at the end of 2023 (RIP Vue 2 👋), the community has rallied around libraries designed specifically for Vue 3. In this article, I am sharing <strong>6 of the most popular Vue.js UI libraries for 2025</strong>—libraries I have loved using or seen gain serious momentum this year.</p>
<p>Whether you are just starting with Vue or deep into building your next big project, these libraries are worth a look. Let’s dive in!</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://giphy.com/gifs/WWF-UK-wwf-uk-wwfuk-2cehTmp8rASyunE10R">https://giphy.com/gifs/WWF-UK-wwf-uk-wwfuk-2cehTmp8rASyunE10R</a></div>
<p> </p>
<hr />
<h1 id="heading-vue-pdf-viewer-flexible-and-powerful-vuejs-pdf-component">Vue PDF Viewer: Flexible and Powerful Vue.js PDF Component</h1>
<p>Just a quick background about what I’m working on. <a target="_blank" href="https://www.vue-pdf-viewer.dev/?utm_source=blog&amp;utm_content=vue-3-ui-libraries-6-most-popular-picks-for-2025">Vue PDF Viewer</a> renders the PDF viewer on your Vue or Nuxt websites so that your users can interact with your PDF document without leaving your sites. The component has over 20 features including theme customization, built-in localization, web responsive and more.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728272164119/9df36d8a-70a3-4856-b47c-417a22d37665.png" alt="Vue PDF Viewer" /></p>
<p>I’d love for you to check <a target="_blank" href="https://www.vue-pdf-viewer.dev/?utm_source=blog&amp;utm_content=vue-3-ui-libraries-6-most-popular-picks-for-2025">Vue PDF Viewer</a> out! Your support means the world and helps me create more awesome content like this. ❤️</p>
<hr />
<h2 id="heading-1-vuetify">1. Vuetify</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737551963407/a3e43d3d-121d-4da4-bcd8-4b8bad8d1643.png" alt class="image--center mx-auto" /></p>
<p>First up is <strong>Vuetify</strong>, the OG Material Design-based UI library for Vue.js. It provides over 100 customizable components for creating beautiful and responsive user interfaces. With its modular design, developers can selectively import components, which keeps the bundle size small and improve performance.</p>
<p>Additionally, Vuetify integrates seamlessly with Nuxt 3 and features powerful theming capabilities where developers can customize their application style and match it with their brand.</p>
<p>As of January 2025, Vuetify has over 40,000 stars (from 38,800 stars in 2024) on GitHub and an average weekly downloads count of close to 600,000. (The <a target="_blank" href="https://npmtrends.com/vuetify">trend line</a> seems to be growing steadily over the years)</p>
<p><strong>Features:</strong></p>
<ul>
<li><p>Over 80 pre-designed components.</p>
</li>
<li><p>Support for server-side rendering and single-page applications.</p>
</li>
<li><p>Extensive documentation and active community support.</p>
</li>
</ul>
<p>Learn more on <a target="_blank" href="https://vuetifyjs.com">https://vuetifyjs.com</a></p>
<h2 id="heading-2-primevue">2. PrimeVue</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737552047034/1f4a54fe-64f2-4db3-a9c3-106405e55745.png" alt class="image--center mx-auto" /></p>
<p><strong>PrimeVue</strong> is a rich set of open-source UI components for Vue applications powered by PrimeTek. It offers over 90 components and 200+ icons making it one of the most comprehensive libraries in the Vue.js community. It's a lightweight library with exclusive Tailwind CSS integration, enabling developers to build complex enterprise-level applications with ease.</p>
<p>PrimeVue also features an intuitive API, allowing developers to quickly customize the components to achieve their desired designs.</p>
<p>As of January 2025, PrimeVue has over 11,000 stars (from 6,800 stars in 2024) on GitHub and an average weekly downloads count of over 280,000 (<a target="_blank" href="https://npmtrends.com/primevue">Huge increase</a> from around 170,000 downloads in 2024).</p>
<p><strong>Features:</strong></p>
<ul>
<li><p>Over 80 versatile components, including charts and data tables.</p>
</li>
<li><p>Accessibility features compliant with WAI-ARIA.</p>
</li>
<li><p>Regular updates and a supportive community.</p>
</li>
</ul>
<p>Learn more on <a target="_blank" href="https://primevue.org/">https://primevue.org/</a></p>
<h2 id="heading-3-element-plus">3. Element Plus</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737552081807/6714511f-6723-4057-9533-2845a744be75.png" alt class="image--center mx-auto" /></p>
<p><strong>Element Plus</strong> is the successor to Element UI, which was designed exclusively for Vue 2.x. While its predecessor focused on Vue 2.x, Element Plus brings new features, modern tools, and an active community, making it a reliable choice for developers around the globe.</p>
<p>With its strong TypeScript support and an API designed for Vue 3’s Composition API, Element Plus offers a smooth development experience. Its UI style is clean and easy to personalize, making it suitable for everything from small projects to large-scale applications. Its documentation and examples further simplify adoption for new users.</p>
<p>As of January 2025, Element Plus has over 25,000 stars (from 22,600 stars in 2024) on GitHub and an average weekly downloads count of over 230,000.</p>
<p><strong>Features</strong>:</p>
<ul>
<li><p>Rich component library with customizable themes.</p>
</li>
<li><p>Internationalization support.</p>
</li>
<li><p>Detailed documentation and community-driven development.</p>
</li>
</ul>
<p>Learn more on <a target="_blank" href="https://element-plus.org/en-US/">https://element-plus.org/en-US/</a></p>
<h2 id="heading-4-quasar">4. Quasar</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737552010246/48d4dd22-364e-4eba-8089-68933f91ed38.png" alt class="image--center mx-auto" /></p>
<p><strong>Quasar</strong> is a high-performance Vue framework that enables developers to build responsive websites, mobile apps, and Electron apps using a single codebase. What makes Quasar, founded since 2015, different and standout from other UI component libraries is that Quasar is not only a UI component library but an entire framework.</p>
<p>Quasar's UI Components feature 70 high performance customizable Material Design components and icons of various styles (bootstrap, material, fontawesome and many more). The documentation is detailed and well thought-out. The library also has pre-built features including animations and functions to handle dates and times.</p>
<p>As of January 2025, Quasar has over 26,000 stars (from 25,000 stars in 2024) on GitHub and an average weekly downloads count of over 150,000.</p>
<p><strong>Features:</strong></p>
<ul>
<li><p>Supports multiple platforms (SPA, SSR, PWA, Mobile, and Desktop).</p>
</li>
<li><p>Comprehensive theming and customization options.</p>
</li>
<li><p>Built-in support for internationalization.</p>
</li>
</ul>
<p>Learn more on <a target="_blank" href="https://quasar.dev/">https://quasar.dev/</a></p>
<h2 id="heading-5-radix-vue">5. Radix Vue</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737551324899/72ba63c8-91af-4089-ba4b-b7c97ff6dc17.png" alt class="image--center mx-auto" /></p>
<p><strong>Radix Vue</strong> is a headless component library crafted specifically for Vue.js, offering developers an accessibility-first approach to building user interfaces. Adapted from the popular Radix UI, it provides a robust set of highly customizable components that integrate seamlessly with Vue 3 applications.</p>
<p>The library prioritizes WAI-ARIA compliance, ensuring all components, such as dropdown menus, sliders, and modals, are fully accessible out of the box. Radix Vue’s headless architecture allows developers to implement their unique styling and behavior without being tied to a specific design system, making it a versatile choice for projects of any scale.</p>
<p>As of January 2025, Radix Vue continues to grow in popularity, with a thriving GitHub community and over 130,000 weekly downloads.</p>
<p><strong>Features:</strong></p>
<ul>
<li><p>Fully accessible components built with WAI-ARIA standards for inclusivity out of the box.</p>
</li>
<li><p>Headless architecture, allowing complete customization of styles and behavior to fit any design system.</p>
</li>
<li><p>Modular and lightweight, optimized for seamless integration into Vue 3 applications.</p>
</li>
</ul>
<p>Learn more on <a target="_blank" href="https://www.radix-vue.com/">https://www.radix-vue.com/</a></p>
<h2 id="heading-6-ant-design-vue">6. Ant Design Vue</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727947139698/1540192a-f9b1-4810-aed3-275128f610b6.png" alt="Ant Design Vue" /></p>
<p><strong>Ant Design Vue (Antdv)</strong> brings the power of the Ant Design ecosystem to Vue.js, offering a polished and professional UI library. Originally developed for React by a team at Alibaba, its Vue implementation has carved out its own space, earning a reputation for its extensive features and developer-friendly design.</p>
<p>Antdv provides a wide array of components, from complex data visualization tools to advanced forms and tree structures. Its focus on scalability and flexibility makes it a strong contender for both small projects and enterprise-grade applications. While the sheer number of features can feel overwhelming at first, the clear documentation and consistent design system make it easy to master.</p>
<p>As of January 2025, Ant Design Vue has over 20,500 stars (from 19,300 stars in 2024) on GitHub and an average weekly downloads count of over 90,000.</p>
<p><strong>Features</strong>:</p>
<ul>
<li><p>Comprehensive component library with consistent design language.</p>
</li>
<li><p>Customizable themes and styles.</p>
</li>
<li><p>Strong community support and regular updates.</p>
</li>
</ul>
<p>Learn more on <a target="_blank" href="https://antdv.com/">https://antdv.com/</a></p>
<h2 id="heading-special-mention-nuxt-ui">Special Mention: Nuxt UI</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737551381613/8507ab05-257b-42be-b753-3fe557b5ec37.png" alt class="image--center mx-auto" /></p>
<p><strong>Nuxt UI</strong> is a UI framework built by the Nuxt team that offers a library of components specifically designed for seamless integration with Nuxt.js projects. It ensures developers have a fast, reliable, and optimized experience when crafting modern web applications.</p>
<p>The library includes a curated selection of lightweight and highly customizable components that prioritize performance and developer productivity. Its components are designed to work out of the box with Nuxt’s powerful features, such as server-side rendering (SSR) and static site generation (SSG), making it an excellent choice for creating scalable and responsive applications.</p>
<p>As of January 2025, Nuxt UI is gaining traction in the Vue.js community, with a rapidly growing GitHub presence and over 460,000 weekly downloads. It’s quickly becoming a go-to solution for those seeking a streamlined and efficient component library tailored for Nuxt.js.</p>
<p><strong>Features:</strong></p>
<ul>
<li><p>Optimized components tailored for seamless integration with Nuxt’s SSR and SSG capabilities.</p>
</li>
<li><p>Lightweight and customizable, designed to enhance performance without sacrificing flexibility.</p>
</li>
<li><p>Backed by the Nuxt team, ensuring consistent updates, detailed documentation, and community support.</p>
</li>
</ul>
<p>Learn more on <a target="_blank" href="https://ui.nuxt.com/">https://ui.nuxt.com/</a></p>
<hr />
<h1 id="heading-conclusion">Conclusion</h1>
<p>The Vue.js ecosystem continues to thrive in 2025, offering developers a wide range of UI component libraries to meet every need, from comprehensive frameworks to lightweight, customizable solutions. Whether you’re building a simple personal project or a complex enterprise application, there’s a library perfectly suited for your needs.  </p>
<p>Each of the libraries brings something unique to the table. To understand which one aligns with your project specific requirements, workflow or design preferences, diving in to explore what each has to offer is probably the best option. 🚀</p>
<hr />
<h1 id="heading-vue-pdf-viewer-the-pdf-viewer-built-for-vuejs-developers">Vue PDF Viewer: The PDF Viewer Built for Vue.js Developers 🚀</h1>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728272164119/9df36d8a-70a3-4856-b47c-417a22d37665.png" alt="Vue PDF Viewer" /></p>
<p>If you enjoyed this article, I encourage you to check out <a target="_blank" href="https://www.vue-pdf-viewer.dev/?utm_source=blog&amp;utm_content=vue-3-ui-libraries-6-most-popular-picks-for-2025">Vue PDF Viewer</a>. Designed specifically for Vue.js applications (small to large), it’s packed with features like easy Vue integration, advanced customization options, responsive layouts, and more. With our developer-friendly APIs and quick-start toolkit, you’ll have a fully functional PDF viewer integrated into your Vue project in no time.</p>
<p>Your support inspires me to create even more valuable content for the Vue community. Thank you for considering Vue PDF Viewer, and happy coding! 🙏</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://giphy.com/gifs/high-five-cat-vnnoqBjIrJ73y">https://giphy.com/gifs/high-five-cat-vnnoqBjIrJ73y</a></div>
]]></content:encoded></item><item><title><![CDATA[📄 Popular PDF Viewers for Vue.js: Which One Is Right for You? 🤔]]></title><description><![CDATA[PDF is a common document that is used digitally everywhere. I have been involved in a few Vue projects that require PDF display. For simple viewing, native browser function or iframe solutions should suffice. For more advanced rendering and interacti...]]></description><link>https://blog.vue-pdf-viewer.dev/popular-pdf-viewers-for-vuejs-which-one-is-right-for-you</link><guid isPermaLink="true">https://blog.vue-pdf-viewer.dev/popular-pdf-viewers-for-vuejs-which-one-is-right-for-you</guid><category><![CDATA[Vue.js]]></category><category><![CDATA[Nuxt]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[TypeScript]]></category><category><![CDATA[Frontend Development]]></category><category><![CDATA[Web Development]]></category><dc:creator><![CDATA[Anson Chieng]]></dc:creator><pubDate>Tue, 10 Dec 2024 11:34:55 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1733843001611/27904f0b-926c-42e2-abfb-7b0825581e42.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>PDF is a common document that is used digitally everywhere. I have been involved in a few Vue projects that require PDF display. For simple viewing, native browser function or iframe solutions should suffice. For more advanced rendering and interactions, you will need dedicated libraries that offer features like theme customization, responsive layouts and reliable support.</p>
<p>Choosing a PDF viewer for a Vue.js application depends on your project’s needs. Here’s a quick breakdown of five options to consider:</p>
<ul>
<li><p><strong>PDF.js (Open Source):</strong> Reliable, no-frills viewing for simple applications.</p>
</li>
<li><p><strong>vue-pdf (Open Source):</strong> Lightweight wrapper for PDF.js, built for Vue.</p>
</li>
<li><p><strong>Nutrient (Paid):</strong> Feature-rich and enterprise-ready, ideal for complex needs.</p>
</li>
<li><p><strong>Vue PDF Viewer (Paid):</strong> Customizable and powerful, built for Vue.</p>
</li>
<li><p><strong>PDF.js Express (Hybrid):</strong> Start with free basics, with optional premium add-ons.</p>
</li>
</ul>
<p>In this article, I'll be comparing five popular PDF libraries for Vue.js. Each library has its strengths and weaknesses, and my goal is to help you pick the best one for your project’s unique needs.</p>
<p><em>Disclaimer: I’m part of the Vue PDF Viewer team.</em></p>
<hr />
<h2 id="heading-importance-of-a-reliable-pdf-viewer">Importance of a Reliable PDF Viewer</h2>
<p>In any Vue.js application where document viewing is essential, a reliable PDF viewer can make all the difference. Whether you’re building a business dashboard, an educational platform, or a document management system, the right PDF viewer streamlines development and enhances the user experience.</p>
<h3 id="heading-key-criteria-for-choosing-a-pdf-viewer-in-vuejs">Key Criteria for Choosing a PDF Viewer in Vue.js</h3>
<p>When selecting a PDF viewer, a few critical factors can determine whether it will fit your project needs:</p>
<ul>
<li><p><strong>Performance:</strong> Fast loading and smooth rendering, especially for large PDFs, are essential.</p>
</li>
<li><p><strong>Ease of Integration:</strong> Libraries that integrate easily into Vue projects save time and simplify maintenance.</p>
</li>
<li><p><strong>Customization:</strong> The ability to style, extend, and configure is important for aligning with specific requirements.</p>
</li>
<li><p><strong>Community &amp; Support:</strong> Documentation and community resources make troubleshooting easier and enhance long-term viability.</p>
</li>
</ul>
<p>With these in mind, let’s explore the top options!</p>
<p><img src="https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExbjJmcXltdHJ2OGFvcHhnbDdiMzRnMmw1Y3d6amgyNnExaHF2ZGdoNCZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/IOUn2qgyH54tH90uJ8/giphy.gif" alt class="image--center mx-auto" /></p>
<hr />
<h2 id="heading-open-source-pdf-viewers">Open Source PDF Viewers</h2>
<h3 id="heading-1-pdfjs">1. PDF.js</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733829370989/a124a05b-dd45-4759-930f-887f7e8b45de.png" alt="PDF.js" /></p>
<p><a target="_blank" href="https://mozilla.github.io/pdf.js/"><strong>PDF.js</strong></a> is a well-known open-source JavaScript library created by Mozilla for rendering PDFs directly in the browser. The library allows developers to display PDF documents without relying on external plugins or native applications. PDF.js renders PDFs by converting each page into HTML5 canvas elements, ensuring that the content is viewable directly in the browser.</p>
<p>Developers who need a simple, cost-effective solution for displaying PDFs in Vue applications often use PDF.js as a base library. Because it’s a standalone JavaScript library, it’s compatible across multiple frameworks. However, it’s not built specifically for Vue, so Vue developers may need to use wrappers or custom integration to make the most of it.</p>
<p><strong>Strengths:</strong></p>
<ul>
<li><p>Large, active community and extensive documentation.</p>
</li>
<li><p>Free to use, with a simple API that allows basic PDF rendering.</p>
</li>
<li><p>Actively maintained, so updates and support are consistent.</p>
</li>
</ul>
<p><strong>Limitations:</strong></p>
<ul>
<li><p>Not specifically designed for Vue; additional setup or wrappers like vue-pdf may be required for integration.</p>
</li>
<li><p>Limited customization, so advanced functionality (e.g., annotations) requires additional coding.</p>
</li>
</ul>
<p><strong>Best Suited For:</strong> Simple applications where basic PDF rendering is suffices. While customization is possible, integrating advanced features with Vue.js requires extensive effort as the library is not designed specifically for the framework.</p>
<h3 id="heading-2-vue-pdf">2. vue-pdf</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733829372831/eddb9b9e-6014-48c9-aa28-2a5c6c6bcad2.png" alt="vue-pdf" /></p>
<p><a target="_blank" href="https://www.npmjs.com/package/vue-pdf"><strong>Vue-pdf</strong></a> is a lightweight wrapper around PDF.js, specifically tailored for Vue applications. While PDF.js itself provides a core PDF rendering engine, vue-pdf simplifies the integration process for Vue developers, making it easier to render PDFs without writing extensive code. By using vue-pdf, Vue developers can enjoy the benefits of PDF.js without needing to manage the complex JavaScript integration manually.</p>
<p>Vue-pdf is ideal for applications that require basic PDF display but don’t need extensive functionality like annotations or form filling. It’s popular in small projects and MVPs where ease of use and quick implementation are prioritized.</p>
<p><strong>Strengths:</strong></p>
<ul>
<li><p>Vue compatibility out-of-the-box, which simplifies integration.</p>
</li>
<li><p>Free and open-source, with a straightforward API.</p>
</li>
<li><p>Great for smaller projects and quick prototyping.</p>
</li>
</ul>
<p><strong>Limitations:</strong></p>
<ul>
<li><p>Limited advanced features, so it’s best suited for basic viewing.</p>
</li>
<li><p>Minimal control over rendering or layout; not ideal for highly customized projects.</p>
</li>
</ul>
<p><strong>Best Suited For:</strong> Lightweight applications with straightforward PDF display needs without default layout. Vue-pdf is widely used in the Vue.js community, but be aware that the library has not been updated in over 3 years, which may lead to potential security and compatibility concerns.</p>
<hr />
<h2 id="heading-paid-pdf-viewers">Paid PDF Viewers</h2>
<h3 id="heading-3-nutrient-formerly-pspdfkit">3. Nutrient (formerly PSPDFKit)</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733829374505/51bd01fc-84a6-4471-98d2-7df0d983529b.png" alt="Nutrient" /></p>
<p><a target="_blank" href="https://www.nutrient.io/"><strong>Nutrient</strong></a> is a premium, enterprise-grade PDF SDK designed to meet the needs of complex applications with advanced PDF requirements. This SDK goes beyond basic PDF viewing, offering interactive features like annotations, form filling, and even document editing. Built with scalability and customization in mind, Nutrient is often chosen by large-scale applications that prioritize security, stability, and extensive functionality.</p>
<p>While Nutrient is not designed specifically for Vue, it can be integrated into Vue applications with some customization. It’s ideal for organizations that need robust PDF features and are willing to invest in a paid solution that comes with dedicated support and a rich feature set.</p>
<p><strong>Strengths:</strong></p>
<ul>
<li><p>Feature-rich, with support for annotations, editing, search, and form filling.</p>
</li>
<li><p>Optimized for large-scale applications, handling complex PDFs efficiently.</p>
</li>
<li><p>Excellent customer support and thorough documentation.</p>
</li>
</ul>
<p><strong>Limitations:</strong></p>
<ul>
<li><p>High cost, which may be a factor for smaller teams or budget-restricted projects.</p>
</li>
<li><p>Integration with Vue may require extensive customization and configuration.</p>
</li>
</ul>
<p><strong>Best Suited For:</strong> Enterprise applications that demand robust, feature-rich PDF functionality such as annotation and editing. Nutrient is ideal for large-scale projects where security, performance, and dedicated support are priorities. However, its high cost and the need for extensive Vue-specific customization may make it less suitable for smaller teams or simpler projects.</p>
<h3 id="heading-4-vue-pdf-viewer">4. Vue PDF Viewer</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733829376265/b1d33ba6-a91c-46ec-b47a-82d03f5f9061.png" alt="Vue PDF Viewer" /></p>
<p><a target="_blank" href="https://www.vue-pdf-viewer.dev/?utm_source=blog&amp;utm_content=popular-pdf-viewers-for-vuejs-which-one-is-right-for-you"><strong>Vue PDF Viewer</strong></a> is a Vue-native solution designed specifically for Vue.js applications. Unlike generic libraries, it integrates seamlessly with Vue projects, offering features that cater to both simple and complex PDF requirements. Its native compatibility ensures that developers can focus more on building their applications and less on managing integration challenges.</p>
<p>Vue PDF Viewer stands out for its ease of use, performance, and the level of customization it offers. It’s particularly suited for projects that demand robust PDF features, such as theme customization, responsive design, and advanced interaction capabilities like annotations.</p>
<p><strong>Strengths:</strong></p>
<ul>
<li><p>Easy to integrate, with Vue-specific functions or methods since it’s Vue-native.</p>
</li>
<li><p>Optimized for quick loading and smooth rendering to handle large PDF files.</p>
</li>
<li><p>Adaptable to any project’s design and functional needs with various APIs to leverage or customize from.</p>
</li>
<li><p>Ensures a seamless experience on both desktop and mobile devices.</p>
</li>
</ul>
<p><strong>Limitations:</strong></p>
<ul>
<li><p>Some advanced enterprise-grade features, such as built-in document editing, may not be available.</p>
</li>
<li><p>While optimized for modern Vue.js frameworks, it is not compatible with older Vue versions (i.e., Vue 2).</p>
</li>
</ul>
<p><strong>Best Suited For:</strong> Vue PDF Viewer is perfect for Vue.js applications requiring a PDF viewer built specifically for Vue. It provides a powerful, native solution with flexibility, high performance, and extensive customization options, making it ideal for projects that prioritize responsive design and seamless user experiences.</p>
<hr />
<h2 id="heading-hybrid-pdf-viewer">Hybrid PDF Viewer</h2>
<h3 id="heading-5-pdfjs-express">5. PDF.js Express</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733829378020/21afe2ea-e808-4ba4-b446-630bf975692f.png" alt="PDF.js Express" /></p>
<p><a target="_blank" href="https://pdfjs.express/"><strong>PDF.js Express</strong></a> offers a unique hybrid model for teams who want flexibility in scaling PDF capabilities. Based on PDF.js, it provides a free version with basic features and the option to unlock premium functionality through paid upgrades. This model is ideal for projects that may need simple viewing at first but might require additional features like annotations, text search, and form filling as they grow.</p>
<p>PDF.js Express is compatible with Vue and is easy to set up, making it accessible to both small projects and larger applications. The option to scale up as needed gives developers flexibility in budgeting and feature selection, allowing projects to remain adaptable.</p>
<p><strong>Strengths:</strong></p>
<ul>
<li><p>Vue-compatible and easy to integrate, with a streamlined setup for quick PDF viewing implementation.</p>
</li>
<li><p>Provides a range of premium features (annotations, form filling, text search) as optional upgrades, which allows developers to start small and add features as the project grows.</p>
</li>
<li><p>Strong documentation and support for both free and premium features, making it a developer-friendly option with a low entry cost.</p>
</li>
</ul>
<p><strong>Limitations:</strong></p>
<ul>
<li><p>Free version is limited in functionality; advanced features require a paid license.</p>
</li>
<li><p>For applications needing high customization or many features, a full SDK like Nutrient or Apryse may be a better choice.</p>
</li>
<li><p>Integration with Vue may require extensive customization since the UI source code is based on React.</p>
</li>
</ul>
<p><strong>Best Suited For:</strong> Projects starting with free features and scaling to premium capabilities like annotations and form filling. It’s best suited for applications with straightforward PDF needs or projects that can accommodate some customization to integrate more advanced functionality over time.</p>
<hr />
<h2 id="heading-honorable-mentions">Honorable Mentions</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733829379934/231a7cdd-aba4-4f6f-9e0b-c99c7c019f24.png" alt="Apryse" /></p>
<p><a target="_blank" href="https://apryse.com/"><strong>Apryse</strong></a> (formerly PDFTron) is a paid PDF SDK that provides advanced PDF processing capabilities for applications that require more than just viewing. Known for its support of various document types, including Word, Excel, and PowerPoint, Apryse is a versatile SDK that fits well in document-heavy applications. Apryse offers extensive manipulation options, including document redaction, digital signatures, and text extraction, making it a go-to for industries with strict document handling requirements, such as finance, healthcare, and legal.</p>
<p>Apryse is also the parent company of PDF.js Express, which offers a hybrid model for scaling PDF capabilities. Like Nutrient, Apryse isn’t Vue-native, but it can be incorporated into Vue projects with some setup. Its comprehensive functionality and emphasis on security make it suitable for projects with high compliance standards.</p>
<p><strong>Best Suited For</strong>: Enterprise applications needing advanced PDF and multi-format handling.</p>
<hr />
<h2 id="heading-table-comparison">Table Comparison</h2>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Library</td><td>Customizable with Vue.js</td><td>PROS</td><td>CONS</td></tr>
</thead>
<tbody>
<tr>
<td>Vue PDF Viewer</td><td>High</td><td>Native Vue.js integration, highly customizable</td><td>Lacks document editing, not supported for older Vue versions (i.e., Vue 2)</td></tr>
<tr>
<td>PDF.js</td><td>Low</td><td>Free, large community, cross-framework</td><td>Not Vue-native, limited advanced features</td></tr>
<tr>
<td>vue-pdf</td><td>High</td><td>Easy Vue integration, free and lightweight</td><td>Limited features, outdated (3+ years)</td></tr>
<tr>
<td>Nutrient</td><td>Moderate</td><td>Feature-rich, enterprise-ready</td><td>Expensive, requires Vue customization</td></tr>
<tr>
<td>PDF.js Express</td><td>Low</td><td>Flexible, optional premium features</td><td>Limited free features, React-based UI</td></tr>
</tbody>
</table>
</div><hr />
<h2 id="heading-conclusion-and-recommendation">Conclusion and Recommendation</h2>
<p>If your projects are relatively small with simple PDF viewing needs, PDF.js should suffice. On the other hand, if you require advanced features like annotation and edit support or customization in Vue.js, Nutrient and Vue PDF Viewer are the best options respectively. PDF.js Express strikes a good balance between flexibility and scalability, making it a strong choice for projects with evolving requirements or variable budgets. Carefully evaluate your project’s requirements and pick the right library for your development process.</p>
<hr />
<h2 id="heading-vue-pdf-viewer-the-pdf-viewer-built-for-vuejs-developers">Vue PDF Viewer: The PDF Viewer Built for Vue.js Developers 🚀</h2>
<p>If you enjoyed this article, I encourage you to check out <a target="_blank" href="https://www.vue-pdf-viewer.dev/?utm_source=blog&amp;utm_content=popular-pdf-viewers-for-vuejs-which-one-is-right-for-you">Vue PDF Viewer</a>. Designed specifically for Vue.js applications (small to large), it’s packed with features like seamless Vue integration, advanced customization options, responsive layouts, and more. With our developer-friendly APIs and quick-start toolkit, you’ll have a fully functional PDF viewer integrated into your Vue project in no time.</p>
<p>Your support keeps me motivated to share more insights and build tools for the developer community. Thank you in advance! 🙏</p>
<p><img src="https://media.giphy.com/media/4J4F61F1XSzjW/giphy.gif?cid=790b7611lxfxzunt5a0farls22pun8gvtq2yhom61m7tx3f3&amp;ep=v1_gifs_search&amp;rid=giphy.gif&amp;ct=g" alt class="image--center mx-auto" /></p>
]]></content:encoded></item><item><title><![CDATA[🔥 How to Render a Beautiful PDF Viewer for Vue.js in Minutes 💅]]></title><description><![CDATA[Since my last post on building PDF Viewer with Vue.js, I have been hard at work to develop a library that just works: Vue PDF Viewer.
https://blog.vue-pdf-viewer.dev/building-a-pdf-viewer-for-vuejs-with-pdfjs-vue3-pdf-app-and-more
 
After being in pr...]]></description><link>https://blog.vue-pdf-viewer.dev/how-to-render-a-beautiful-pdf-viewer-for-vuejs-in-minutes</link><guid isPermaLink="true">https://blog.vue-pdf-viewer.dev/how-to-render-a-beautiful-pdf-viewer-for-vuejs-in-minutes</guid><category><![CDATA[Vue.js]]></category><category><![CDATA[Nuxt.js]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[TypeScript]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[Frontend Development]]></category><dc:creator><![CDATA[watcharakorn]]></dc:creator><pubDate>Tue, 24 Sep 2024 16:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1732705561084/170875ce-794a-4af5-96ed-75d6ba4b1c36.avif" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Since my last post on building PDF Viewer with Vue.js, I have been hard at work to develop a library that just works: <a target="_blank" href="https://www.vue-pdf-viewer.dev/?utm_source=blog&amp;utm_content=how-to-render-a-beautiful-pdf-viewer-for-vuejs-in-minutes">Vue PDF Viewer</a>.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://blog.vue-pdf-viewer.dev/building-a-pdf-viewer-for-vuejs-with-pdfjs-vue3-pdf-app-and-more">https://blog.vue-pdf-viewer.dev/building-a-pdf-viewer-for-vuejs-with-pdfjs-vue3-pdf-app-and-more</a></div>
<p> </p>
<p>After being in private beta for a few months, we officially launched <a target="_blank" href="https://www.vue-pdf-viewer.dev/?utm_source=blog&amp;utm_content=how-to-render-a-beautiful-pdf-viewer-for-vuejs-in-minutes">Vue PDF Viewer</a> earlier this month. In this article, I'll be sharing with you how to render a PDF in Vue.js in just minutes, along with a few use cases to help you make the most out of this library.</p>
<hr />
<h2 id="heading-why-vue-pdf-viewer">Why Vue PDF Viewer?</h2>
<p>Let’s start with why <a target="_blank" href="https://www.vue-pdf-viewer.dev/?utm_source=blog&amp;utm_content=how-to-render-a-beautiful-pdf-viewer-for-vuejs-in-minutes">Vue PDF Viewer</a> stands out. Here’s a quick rundown of its key features:</p>
<ul>
<li><p><strong>Built for Vue</strong>: Designed specifically for Vue.js developers, Vue PDF Viewer is designed using familiar Vue’s component-based structure, syntax and state management for Vue.js developers to customize natively.</p>
</li>
<li><p><strong>Quick Setup</strong>: Go from zero to a fully functional PDF viewer in just 3 simple steps.</p>
</li>
<li><p><strong>Customizable</strong>: Supports themes, responsive layouts, and custom icons, allowing you to tailor the viewer to fit your app’s design.</p>
</li>
<li><p><strong>High Performance</strong>: Optimized for handling multiple PDFs without sacrificing speed or performance.</p>
</li>
</ul>
<p>Now, let’s dive into the step-by-step process to get started with Vue PDF Viewer.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExd2R4bmwxb2Q3YmVwcGpyMHl3bnZhOXl2ZXI2ZzF2NWU3dWczN2k2MCZlcD12MV9naWZzX3NlYXJjaCZjdD1n/CjmvTCZf2U3p09Cn0h/giphy.gif">https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExd2R4bmwxb2Q3YmVwcGpyMHl3bnZhOXl2ZXI2ZzF2NWU3dWczN2k2MCZlcD12MV9naWZzX3NlYXJjaCZjdD1n/CjmvTCZf2U3p09Cn0h/giphy.gif</a></div>
<p> </p>
<hr />
<h2 id="heading-displaying-a-pdf-viewer-component">Displaying a PDF Viewer Component</h2>
<p><a target="_blank" href="https://docs.vue-pdf-viewer.dev/introduction/getting-started.html?utm_source=medium&amp;utm_content=how-to-render-a-beautiful-pdf-viewer-for-vuejs-in-minutes">Vue PDF Viewer</a> supports Vue 3. It also works seamlessly across a wide range of environments, including:</p>
<ul>
<li><p>Vue 3 – Composition API (TypeScript, JavaScript)</p>
</li>
<li><p>Vue 3 – Options API (TypeScript, JavaScript)</p>
</li>
<li><p>Vue 3 – Server-Side rendering (TypeScript)</p>
</li>
<li><p>Nuxt</p>
</li>
<li><p>VitePress</p>
</li>
<li><p>Quasar</p>
</li>
</ul>
<p>For this demo, I’ll show you how to add the Vue PDF Viewer component to a Vue app.</p>
<h3 id="heading-step-1-adding-the-library">Step 1: Adding the Library</h3>
<p>To get started, add the Vue PDF Viewer library to your project. It’s a quick and easy installation.</p>
<pre><code class="lang-bash">bun add @vue-pdf-viewer/viewer
</code></pre>
<p><em>Remark: You can use</em> <code>yarn</code>, <code>npm</code> or <code>pnpm</code>.</p>
<h3 id="heading-step-2-importing-the-component">Step 2: Importing the Component</h3>
<p>Next, we’ll import the PDF viewer component into your Vue application.</p>
<pre><code class="lang-plaintext">&lt;script setup&gt;
  import { VPdfViewer } from "@vue-pdf-viewer/viewer";
&lt;/script&gt;
</code></pre>
<h3 id="heading-step-3-render-the-component">Step 3: Render the Component</h3>
<p>Finally, render the component and pass in the required props to display your PDF document.</p>
<pre><code class="lang-plaintext">&lt;script setup&gt;
import { VPdfViewer } from "@vue-pdf-viewer/viewer";
&lt;/script&gt;
&lt;template&gt;
  &lt;div :style="{ width: '1028px', height: '700px' }"&gt;
    &lt;VPdfViewer
      src="https://raw.githubusercontent.com/mozilla/pdf.js/ba2edeae/web/compressed.tracemonkey-pldi-09.pdf"
    /&gt;
  &lt;/div&gt;
&lt;/template&gt;
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728272131928/bf3dce0c-2d70-4b34-a7ad-df3b266d639b.png" alt="An image rendering a Vue PDF Viewer component" /></p>
<p>That’s it! In just a few steps, you have integrated a fully responsive and customizable PDF viewer into your Vue app!</p>
<p><em>Remark: Since the Vue PDF Viewer is a component, you can initiate multiple instances of the component in the same page independently.</em></p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExd3J4bjhyaWl2NXQzNmR2NWV5d2l0Y2ZyZHZqNWUyeGNodmNoZGEzeCZlcD12MV9naWZzX3NlYXJjaCZjdD1n/VPRABLhiu6sJAn5FEK/giphy.gif">https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExd3J4bjhyaWl2NXQzNmR2NWV5d2l0Y2ZyZHZqNWUyeGNodmNoZGEzeCZlcD12MV9naWZzX3NlYXJjaCZjdD1n/VPRABLhiu6sJAn5FEK/giphy.gif</a></div>
<p> </p>
<hr />
<h2 id="heading-common-use-cases">Common Use Cases</h2>
<p>Want to know more about how you can modify Vue PDF Viewer to fit your needs? Here are some common use cases:</p>
<h3 id="heading-change-themes-to-match-your-site">Change Themes to Match Your Site</h3>
<p>You can easily adjust the viewer’s theme to match your website’s design. Whether your site uses light or dark modes or other types of color scheme, VPV can be customized to fit the current settings, ensuring a consistent look and feel across your entire platform.</p>
<pre><code class="lang-css">&lt;<span class="hljs-selector-tag">script</span> <span class="hljs-selector-tag">setup</span>&gt;
  ...
&lt;/<span class="hljs-selector-tag">script</span>&gt;
&lt;<span class="hljs-selector-tag">style</span> <span class="hljs-selector-tag">scoped</span>&gt;
<span class="hljs-selector-pseudo">:deep(.vpv-variables)</span> {
  <span class="hljs-attribute">--vpv-container-border-color</span>: lightblue;
  <span class="hljs-attribute">--vpv-toolbar-background-color</span>: mintcream;
  <span class="hljs-attribute">--vpv-toolbar-color</span>: black;
  <span class="hljs-attribute">--vpv-toolbar-border-color</span>: lightblue;
  <span class="hljs-attribute">--vpv-icon-active-background</span>: grey;
  <span class="hljs-attribute">--vpv-sidebar-content-background-color</span>: mintcream;
  <span class="hljs-attribute">--vpv-sidebar-content_thumbnail-page-number-font-size</span>: <span class="hljs-number">10px</span>;
  <span class="hljs-attribute">--vpv-sidebar-content_thumbnail-focused-border-color</span>: darkslategrey;
  <span class="hljs-attribute">--vpv-pages-container-background</span>: mintcream;
}

<span class="hljs-comment">/* To override variables in dark mode */</span>
<span class="hljs-selector-pseudo">:deep(.vpv-variables.vpv-variables__dark)</span> {
  <span class="hljs-attribute">--vpv-container-border-color</span>: blue;
  <span class="hljs-attribute">--vpv-toolbar-background-color</span>: darkgrey;
  <span class="hljs-attribute">--vpv-toolbar-color</span>: white;
  <span class="hljs-attribute">--vpv-toolbar-border-color</span>: blue;
  <span class="hljs-attribute">--vpv-icon-active-background</span>: grey;
  <span class="hljs-attribute">--vpv-sidebar-content-background-color</span>: darkgrey;
  <span class="hljs-attribute">--vpv-sidebar-content_thumbnail-focused-border-color</span>: white;
  <span class="hljs-attribute">--vpv-pages-container-background</span>: darkgrey;
}
&lt;/<span class="hljs-selector-tag">style</span>&gt;
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728272133348/9a05afda-8f58-43d0-ac29-87462f4d9416.gif" alt="A gif showing a Vue PDF Viewer component switching to a dark theme." class="image--center mx-auto" /></p>
<h3 id="heading-adjust-web-responsive-breakpoint">Adjust Web Responsive Breakpoint</h3>
<p>By default, the Vue PDF Viewer component resizes responsively at <code>768px</code>. If you wish to adjust the breakpoint to be higher, perhaps because you using text instead of graphic as icons, you can easily specify breakpoint to trigger responsive style.</p>
<pre><code class="lang-css">&lt;<span class="hljs-selector-tag">style</span> <span class="hljs-selector-tag">scoped</span>&gt;
  <span class="hljs-selector-pseudo">:deep(.vpv-variables)</span> {
    <span class="hljs-attribute">--vpv-container-width-sm</span>: <span class="hljs-number">1000px</span>;
  }
&lt;/<span class="hljs-selector-tag">style</span>&gt;
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728272135362/009260a7-16e4-4494-80d8-9889174f3ffa.gif" alt="A gif showing a Vue PDF Viewer component resizing responsively with a higher breakpoint than that of a default." class="image--center mx-auto" /></p>
<p>Or if you need the PDF viewer component to resize even below the default breakpoint.</p>
<pre><code class="lang-css">&lt;<span class="hljs-selector-tag">style</span> <span class="hljs-selector-tag">scoped</span>&gt;
  <span class="hljs-selector-pseudo">:deep(.vpv-variables)</span> {
    <span class="hljs-attribute">--vpv-container-width-sm</span>: <span class="hljs-number">600px</span>;
  }
&lt;/<span class="hljs-selector-tag">style</span>&gt;
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728272137023/c3836b9c-572e-494c-8c47-cdd9e673fd83.gif" alt="A gif showing a Vue PDF Viewer component resizing responsively with a lower breakpoint than that of a default." class="image--center mx-auto" /></p>
<h3 id="heading-customize-any-icon">Customize Any Icon</h3>
<p>Vue PDF Viewer provides flexibility when it comes to customizing the user interface. You can easily swap out default icons with custom ones, giving you the ability to maintain brand consistency or match your app’s style.</p>
<pre><code class="lang-plaintext">&lt;script setup lang="ts"&gt;
import { VPdfViewer } from "@vue-pdf-viewer/viewer";
const pdfFileSource =
  "https://raw.githubusercontent.com/mozilla/pdf.js/ba2edeae/web/compressed.tracemonkey-pldi-09.pdf";
&lt;/script&gt;
&lt;template&gt;
  &lt;div :style="{ width: '1028px', height: '700px' }"&gt;
    &lt;VPdfViewer :src="pdfFileSource"&gt;
      &lt;template #iconSearch&gt;
        &lt;span&gt;Search&lt;/span&gt;
      &lt;/template&gt;
    &lt;/VPdfViewer&gt;
  &lt;/div&gt;
&lt;/template&gt;
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728272138488/d6a224af-8cba-4057-8a79-e75cd429707b.png" alt="An image showing a Vue PDF Viwer component with a custom search icon using text." /></p>
<p>If you are interested in learning more about the library, feel free to check out the <a target="_blank" href="https://docs.vue-pdf-viewer.dev/?utm_source=blog&amp;utm_content=how-to-render-a-beautiful-pdf-viewer-for-vuejs-in-minutes">docs</a> or try out our <a target="_blank" href="https://demo.vue-pdf-viewer.dev/?vpv-locale=en_US&amp;utm_source=blog&amp;utm_content=how-to-render-a-beautiful-pdf-viewer-for-vuejs-in-minutes">demo</a>.</p>
<hr />
<h2 id="heading-conclusion">Conclusion</h2>
<p>In just a few steps, you can have a fully functioning, responsive, and customizable PDF viewer embedded into your Vue.js application using Vue PDF Viewer. Whether you are building a simple document viewer or a more complex app, Vue PDF Viewer makes PDF rendering effortless and beautiful.</p>
<p>Thank you for taking the time to read this post. And I look forward to seeing what you build with <a target="_blank" href="https://www.vue-pdf-viewer.dev/?utm_source=blog&amp;utm_content=how-to-render-a-beautiful-pdf-viewer-for-vuejs-in-minutes">Vue PDF Viewer</a>! 🙏</p>
<p><img src="https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExdGFuaTFwbWFkc2VhZzg1NHRzMWRiZTZlcW94cTg0NmMzeXQ3Y2c5OCZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/5g1WreDOnHbqXpNhhz/giphy.gif" alt class="image--center mx-auto" /></p>
]]></content:encoded></item><item><title><![CDATA[✨Building a PDF Viewer for Vue.js with PDF.js, vue3-pdf-app and more 🚀]]></title><description><![CDATA[As someone who has worked on several Vue.js projects in the past, I know firsthand the importance of having a great PDF Viewer to enhance the user experience. Whether it's displaying important documents, presenting reports, or sharing content, PDF vi...]]></description><link>https://blog.vue-pdf-viewer.dev/building-a-pdf-viewer-for-vuejs-with-pdfjs-vue3-pdf-app-and-more</link><guid isPermaLink="true">https://blog.vue-pdf-viewer.dev/building-a-pdf-viewer-for-vuejs-with-pdfjs-vue3-pdf-app-and-more</guid><category><![CDATA[Vue.js]]></category><category><![CDATA[Nuxt.js]]></category><category><![CDATA[TypeScript]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[frontend]]></category><category><![CDATA[Frontend Development]]></category><dc:creator><![CDATA[watcharakorn]]></dc:creator><pubDate>Mon, 18 Mar 2024 16:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1732705183346/a4a93080-2a61-44cb-8d53-5fbe7450f8df.avif" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>As someone who has worked on several Vue.js projects in the past, I know firsthand the importance of having a great PDF Viewer to enhance the user experience. Whether it's displaying important documents, presenting reports, or sharing content, PDF viewers provide a seamless way to access and interact with PDF files.</p>
<p>In this article, I'll be sharing with you four different methods that I've personally used for building a PDF Viewer in Vue.js: iFrame, PDF with New Tab, PDF.js, and vue3-pdf-app. Each method offers unique features and benefits, catering to various project requirements.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExNWRvbjBibHlpNHVsMHU3cG9kczh1d3pua3E1YzJ1ejE5OWtudDFlayZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/3o7TKUM3IgJBX2as9O/giphy.gif">https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExNWRvbjBibHlpNHVsMHU3cG9kczh1d3pua3E1YzJ1ejE5OWtudDFlayZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/3o7TKUM3IgJBX2as9O/giphy.gif</a></div>
<p> </p>
<hr />
<h2 id="heading-what-is-so-important-about-pdf">What is so important about PDF?</h2>
<p>Rendering PDFs on websites has a wide range of practical use cases that some of you may have come across. Here are a few examples of these use cases:</p>
<ol>
<li><p>Product Manuals: As a senior developer, you know that product manuals are an essential resource for customers. By rendering product manuals as PDFs, users can access them on any device, view them in high resolution, and even print them out if needed. PDFs allow you to preserve the original layout and formatting while adding interactive elements like hyperlinks and bookmarks to make navigation easy.</p>
</li>
<li><p>Legal Contracts: Contracts are an important legal document that requires accuracy and consistency. By rendering legal contracts as PDFs, you can ensure that they cannot be edited or tampered with, and that they can be quickly and easily signed online with digital signatures.</p>
</li>
<li><p>E-books and Online Publications: Many websites offer e-books, case studies, and other online publications. By rendering this content as PDFs, readers can enjoy a familiar reading experience, similar to reading a physical book or magazine, with the ability to zoom in, annotate, and bookmark pages.</p>
</li>
<li><p>Educational Materials: As a developer, you may find yourself working on e-learning websites or educational platforms. By rendering course materials and study guides as PDFs, you can present the content in an easy-to-read, visually appealing way.</p>
</li>
</ol>
<hr />
<h2 id="heading-vue-pdf-viewer-flexible-and-powerful-vuejs-pdf-component">Vue PDF Viewer: Flexible and Powerful Vue.js PDF Component</h2>
<p>Just a quick background about what I’m working on. <a target="_blank" href="https://www.vue-pdf-viewer.dev/?utm_source=blog&amp;utm_content=building-a-pdf-viewer-for-vuejs">Vue PDF Viewer</a> renders the PDF viewer on your Vue or Nuxt websites so that your users can interact with your PDF document without leaving your sites. The component has over 20 features including theme customization, built-in localization, web responsive and more.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728272164119/9df36d8a-70a3-4856-b47c-417a22d37665.png" alt="Vue PDF Viewer" /></p>
<p>I would be grateful if you could check <a target="_blank" href="https://www.vue-pdf-viewer.dev/?utm_source=blog&amp;utm_content=building-a-pdf-viewer-for-vuejs">Vue PDF Viewe</a>r out. It will encourage me to make even more contents ❤️‍🔥</p>
<hr />
<h2 id="heading-method-1-iframe">Method 1: iFrame</h2>
<p>iFrame provides a straightforward approach to embed PDF files and leverage the browser's built-in PDF viewing capabilities. Here's how you can implement it in Vue.js:</p>
<ol>
<li><p>Install Vue.js and create a new Vue project using the Vite.</p>
</li>
<li><p>Add an iFrame element to your Vue component template.</p>
</li>
<li><p>Set the src attribute of the iFrame to the URL or path of the PDF file.</p>
</li>
</ol>
<p>Here is the <a target="_blank" href="https://codesandbox.io/p/devbox/pdf-vg3g97?file=%2Fsrc%2Fcomponents%2FIframe.vue">link</a> to the code sample.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728272165910/4ae2fc51-bed6-4fbc-8bf0-cda055a798ba.png" alt="iFrame demo" /></p>
<p>Using iFrame has its pros and cons:</p>
<p><strong>Pros</strong></p>
<ul>
<li><p>Simple implementation</p>
</li>
<li><p>Relies on the browser's native PDF viewer</p>
</li>
<li><p>Display PDF file as part of a website</p>
</li>
</ul>
<p><strong>Cons</strong></p>
<ul>
<li><p>Cannot customize because it's using the browser's native pdf function</p>
</li>
<li><p>Potential compatibility issues with different browsers and versions</p>
</li>
</ul>
<p><strong>When to use</strong> Looking for a quick set up without a need for PDF viewer to have UI consistency.</p>
<hr />
<h2 id="heading-method-2-pdf-with-new-tab">Method 2: PDF with New Tab</h2>
<p>The second method involves opening the PDF in a new browser tab. Here's an overview of implementing this method in Vue.js:</p>
<ol>
<li><p>Create a link or button element in your Vue component template.</p>
</li>
<li><p>Add an onclick event handler to open a new browser tab with the PDF URL.</p>
</li>
</ol>
<p>Using a new tab approach offers the following pros and cons:</p>
<p><strong>Pros</strong></p>
<ul>
<li><p>Simple implementation</p>
</li>
<li><p>Direct interaction with the PDF content</p>
</li>
</ul>
<p><strong>Cons</strong></p>
<ul>
<li><p>User experience cannot be controlled</p>
</li>
<li><p>Potential compatibility issues with different browsers and versions</p>
</li>
</ul>
<p><strong>When to use</strong> Similar to method 1 and when you want the viewing experience of PDF file to be separated from the main website. For example, you do not want to add a PDF iFrame.</p>
<hr />
<h2 id="heading-method-3-pdfjs">Method 3: PDF.js</h2>
<p>PDF.js is a powerful JavaScript library maintained by Mozilla that allows rendering and manipulation of PDF files directly in web browsers. It provides extensive features and capabilities for displaying PDFs in Vue.js applications. To utilize PDF.js in Vue.js, follow these steps:</p>
<ol>
<li><p>Install the PDF.js library using a script tag.</p>
</li>
<li><p>Create a Vue component to display the PDF viewer</p>
</li>
<li><p>incorporate the PDF.js into the component to render PDF files.</p>
</li>
</ol>
<p>I have added a simple PDF Viewer using PDF.js in a Vue website. You may find the codes <a target="_blank" href="https://codesandbox.io/p/devbox/pdf-vg3g97?file=%2Fsrc%2Fcomponents%2FPDFjs.vue">here</a>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728272167809/3425bf73-9275-4c5e-961d-b966eee604ce.png" alt="PDF.js demo" /></p>
<p>Let's discuss the advantages and disadvantages of using PDF.js:</p>
<p><strong>Pros</strong></p>
<ul>
<li><p>Advanced PDF rendering functionality</p>
</li>
<li><p>Cross-browser compatibility</p>
</li>
<li><p>Extensive customization options</p>
</li>
<li><p>Well maintained</p>
</li>
<li><p>Big community</p>
</li>
</ul>
<p><strong>Cons</strong></p>
<ul>
<li><p>May require time and effort to learn the syntax and best practices of the library</p>
</li>
<li><p>Not user-friendly technical document</p>
</li>
<li><p>Not easy to customize with JavaScript such as Angular, React and Vue</p>
</li>
<li><p>Increased complexity when handling more complex PDF interactions</p>
</li>
</ul>
<p><strong>When to use</strong> If you want to customize the PDF viewer UI and integrate it as part of a Vue website.</p>
<hr />
<h2 id="heading-method-4-vue3-pdf-app">Method 4: vue3-pdf-app</h2>
<p>vue-pdf is a convenient package specifically designed for Vue.js developers to build PDF viewers. It acts as a wrapper around PDF.js, simplifying the integration process. Here's how you can get started with vue3-pdf-app in Vue.js:</p>
<ol>
<li><p>Install the vue3-pdf-app package using npm or yarn</p>
</li>
<li><p>Import the vue3-pdf-app component to display PDF</p>
</li>
</ol>
<p>Please find the demo <a target="_blank" href="https://codesandbox.io/p/sandbox/vue3-pdf-app-forked-p2zygn?file=%2Fsrc%2FApp.vue%3A5%2C8">here</a>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728272169133/bb6f9694-0c54-491c-b155-4fedf2b43fa9.png" alt="vue3-pdf-app demo" /></p>
<p>Let's explore the advantages and disadvantages of using vue-pdf:</p>
<p><strong>Pros</strong></p>
<ul>
<li><p>Easy integration with Vue.js projects</p>
</li>
<li><p>Simplified API for PDF rendering</p>
</li>
<li><p>Customizable viewer options</p>
</li>
</ul>
<p><strong>Cons</strong></p>
<ul>
<li><p>Support only Vue 3.2 with vue-cli which is not no longer recommended by Vue</p>
</li>
<li><p>Cannot run on Vite</p>
</li>
<li><p>Not maintained</p>
</li>
<li><p>Small community</p>
</li>
</ul>
<p><strong>When to use</strong> Actually, I don't recommend using this library because of it only support Vue 3.2.</p>
<hr />
<h2 id="heading-comparison-summary">Comparison Summary</h2>
<p>There are multiple methods available to build a PDF viewer for Vue.js. The iFrame approach is simple and relies on the browser's built-in capabilities. Displaying PDFs on the browser provides more control but requires user installation of a PDF viewer plugin. PDF.js offers advanced rendering features and cross-browser compatibility. For Vue.js developers, the vue-pdf package provides a convenient wrapper for PDF.js, simplifying the implementation process. Choose the method that best suits your project requirements and delivers the desired user experience</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExMGo1N29zbjd2aG5paHM1ZWE5dnF3M2pkeTE1YW0yNHB1N285aDY1cCZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/eIqj0vevEQ6lLFUeTZ/giphy.gif">https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExMGo1N29zbjd2aG5paHM1ZWE5dnF3M2pkeTE1YW0yNHB1N285aDY1cCZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/eIqj0vevEQ6lLFUeTZ/giphy.gif</a></div>
<p> </p>
<hr />
<h2 id="heading-is-there-a-better-solution">Is there a Better Solution?</h2>
<p>For customization purposes, using iFrame or Open with New Tab may not be suitable. Although PDF.js is a possible option, using it effectively can take time and effort that Vue.js developers may not want to commit. It's because of all these reasons that the company I'm working for is building a new library, <a target="_blank" href="https://www.vue-pdf-viewer.dev/?utm_source=blog&amp;utm_content=building-a-pdf-viewer-for-vuejs">Vue PDF Viewer</a>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728272171133/0c0c4bf7-8fae-446e-8bea-88bd40141e82.gif" alt="Video demo of Vue PDF Viewer" class="image--center mx-auto" /></p>
<ol>
<li><p><strong>Made for Vue.js:</strong> <a target="_blank" href="https://www.vue-pdf-viewer.dev/?utm_source=blog&amp;utm_content=building-a-pdf-viewer-for-vuejs">Vue PDF Viewer</a> library is crafted to seamlessly integrate with Vue.js. With just a few lines of code. What's more, the library offers extensive customization options, enabling developers to easily match the PDF viewer's theme to their website's design.</p>
</li>
<li><p><strong>Compatible with Vite:</strong> For Vue.js developers who leverage Vite as their development tool, the library brings additional advantages. Developers can take advantage of unmatched performance and build speed.</p>
</li>
<li><p><strong>Extensive Feature Set:</strong> Come equipped with an extensive set of over 20 features, catering to a wide range of user requirements. From essential functionalities like text highlighting and bookmarking, to advanced options such as search functionality, web responsive and localization.</p>
</li>
<li><p><strong>User-Friendly Technical Doc:</strong> Get started quickly with our starter toolkit. The documentation includes clear instructions, code examples, and extensive API references.</p>
</li>
<li><p><strong>Reliable Support:</strong> We understand the importance of reliable support during the integration process. From a responsive customer support team to regular updates addressing bug fixes and feature enhancements.</p>
</li>
</ol>
<p>If you find this library helpful, please check out please check out <a target="_blank" href="https://www.vue-pdf-viewer.dev/?utm_source=blog&amp;utm_content=building-a-pdf-viewer-for-vuejs">Vue PDF Viewer</a>. It would encourage me to continue creating even more contents. Thank you in advance! 🙏</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExdzUxaWZzM2IwcDRtcm9mYmRzeWZ1c2hpc29tN2RucmQ1OXo3cmoyMSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/3oz8xIsloV7zOmt81G/giphy.gif">https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExdzUxaWZzM2IwcDRtcm9mYmRzeWZ1c2hpc29tN2RucmQ1OXo3cmoyMSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/3oz8xIsloV7zOmt81G/giphy.gif</a></div>
]]></content:encoded></item><item><title><![CDATA[⚡️Top 6 Vue.js UI Libraries (Vue 3) Trending in 2024 🔥]]></title><description><![CDATA[Edit: Previously I wrote about the "6 Most Popular Vue.js UI Libraries (Vue 3) in 2023". As we are now in 2024, I have revisited the different libraries and updated them for the current year 🎉
Vue.js, a JavaScript framework, has been gaining a lot o...]]></description><link>https://blog.vue-pdf-viewer.dev/top-6-vuejs-ui-libraries-vue-3-trending-in-2024</link><guid isPermaLink="true">https://blog.vue-pdf-viewer.dev/top-6-vuejs-ui-libraries-vue-3-trending-in-2024</guid><category><![CDATA[Vue.js]]></category><category><![CDATA[Nuxt.js]]></category><category><![CDATA[TypeScript]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[Frontend Development]]></category><dc:creator><![CDATA[Anson Chieng]]></dc:creator><pubDate>Mon, 11 Mar 2024 16:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1732704625089/3b56ac6e-5eda-41fa-b76e-90c208680a7d.avif" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>Edit: Previously I wrote about the "</em><a target="_blank" href="https://blog.vue-pdf-viewer.dev/6-most-popular-vuejs-ui-libraries-vue-3-in-2023"><em>6 Most Popular Vue.js UI Libraries (Vue 3) in 2023</em></a><em>". As we are now in 2024, I have revisited the different libraries and updated them for the current year 🎉</em></p>
<p>Vue.js, a JavaScript framework, has been gaining a lot of attention in recent years due to its simplicity, flexibility, and performance. Also, User Interface (UI) component libraries have become an essential aspect of web development, providing a fast and convenient way to build beautiful and responsive user interfaces.</p>
<p>Vue 3 has become the default choice to build modern applications since Vue 2 reaching its end of life on December 31, 2023. The need for UI component libraries designed specifically for Vue 3 has risen. In this article, we will take a look at the six most popular Vue.js UI component libraries for 2024, categorized based on their popularity within English and Chinese-speaking communities.</p>
<p>I decided to categorize this way because of massive popularity of Vue.js in China according to <a target="_blank" href="https://www.freecodecamp.org/news/between-the-wires-an-interview-with-vue-js-creator-evan-you-e383cbf57cc4/">an interview</a> with Evan You, the creator of Vue.js, who was born in China and grew up in a city near Shanghai.</p>
<p>Moreover, Vue has well written documents in Chinese. As teams from big companies in China such as Alibaba, Tencent and Baidu started using Vue.js, all these factors may have contributed to its popularity in the country.</p>
<hr />
<h2 id="heading-vue-pdf-viewer-flexible-and-powerful-vuejs-pdf-component">Vue PDF Viewer: Flexible and Powerful Vue.js PDF Component</h2>
<p>Just a quick background about what I’m working on. <a target="_blank" href="https://www.vue-pdf-viewer.dev/?utm_source=blog&amp;utm_content=top-6-vuejs-ui-libraries-vue-3-trending-in-2024">Vue PDF Viewer</a> renders the PDF viewer on your Vue or Nuxt websites so that your users can interact with your PDF document without leaving your sites. The component has over 20 features including theme customization, built-in localization, web responsive and more.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727947131835/59fe35c4-93e4-4cef-9e79-88fd84d5fc7f.png" alt="Vue PDF Viewer" /></p>
<p>I would be grateful if you could check <a target="_blank" href="https://www.vue-pdf-viewer.dev/?utm_source=blog&amp;utm_content=top-6-vuejs-ui-libraries-vue-3-trending-in-2024">Vue PDF Viewer</a> out. It will encourage me to make even more contents ❤️‍🔥</p>
<hr />
<h2 id="heading-english-focused-community">English focused community</h2>
<h3 id="heading-1-vuetify">1. Vuetify</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727947133471/c531ad19-e5e9-4993-8164-5f69ae5f4f9f.png" alt="Vuetify" /></p>
<p>Vuetify is a popular Vue.js UI component library based on Material Design specifications. It provides over 100 customizable components for creating beautiful and responsive user interfaces. With its modular design, developers can selectively import components, which keeps the bundle size small and improve performance.</p>
<p>Additionally, Vuetify integrates seamlessly with Nuxt 3 and features powerful theming capabilities where developers can customize their application style and match it with their brand.</p>
<p>As of February 2024, Vuetify has over 38,800 stars (from 37,900 stars in 2023) on GitHub and an average weekly downloads count of close to 500,000. (The <a target="_blank" href="https://npmtrends.com/vuetify">trend line</a> seems to be growing steadily over the years)</p>
<p>Learn more on <a target="_blank" href="https://vuetifyjs.com">https://vuetifyjs.com</a></p>
<p><em>Remark: There are still a couple of Vuetify 2 components including calendar, overflow-btn, speed-dial, time-picker and treeview that are not yet available in Vuetify 3. According to official Vuetify guide, they will be released by Vuetify Labs when development is completed.</em></p>
<h3 id="heading-2-quasar">2. Quasar</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727947134962/174409a3-585d-4328-b0a5-4b4fd665ccde.png" alt="Quasar" /></p>
<p>Quasar's UI Components feature 70 high performance customizable Material Design components and icons of various styles (bootstrap, material, fontawesome and many more). The documentation is detailed and well thought-out. The library also has pre-built features including animations and functions to handle dates and times.</p>
<p>What makes Quasar, founded since 2015, different and standout from other UI component libraries is that Quasar is not only a UI component library but a dynamic Vue framework. You can develop Vue.js desktop, web and mobile applications with a single codebase. As the saying goes, write once and use everywhere.</p>
<p>As of February 2024, Quasar has over 25,000 stars (from 24,200 stars in 2023) on GitHub and an average weekly downloads count of over 100,000.</p>
<p>Learn more on <a target="_blank" href="https://quasar.dev/">https://quasar.dev/</a></p>
<h3 id="heading-3-primevue">3. PrimeVue</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727947136401/94d98a40-22cf-44ed-b0ea-2b07c3186e76.png" alt="PrimeVue" /></p>
<p>PrimeVue is a sleek Vue.js component library that offers over 90 components and 200+ icons making it one of the most comprehensive libraries in the Vue.js community. It's a lightweight library with exclusive Tailwind CSS integration, enabling developers to build complex enterprise-level applications with ease.</p>
<p>PrimeVue is powered by PrimeTek, which serves millions of developers of Fortune 500 companies such as Intel, Nvidia and American Express, lending it massive credibility in the enterprise space.</p>
<p>PrimeVue also features an intuitive API, allowing developers to quickly customize the components to achieve their desired designs.</p>
<p>As of February 2024, PrimeVue has over 6,800 stars (from 4,300 stars in 2023) on GitHub and an average weekly downloads count of over 170,000 (<a target="_blank" href="https://npmtrends.com/primevue">Huge increase</a> from around 100,000 downloads in September 2023).</p>
<p>Learn more on <a target="_blank" href="https://primevue.org/">https://primevue.org/</a></p>
<hr />
<h2 id="heading-chinese-focused-community">Chinese focused community</h2>
<h3 id="heading-1-element-plus">1. Element Plus</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727947137699/99a2ceb2-b8c8-435a-b7a3-c16032e0a04a.png" alt="Element Plus" /></p>
<p>Element Plus is a community developed project born from Element UI which supports only Vue 2.X. Due to its predecessor's popularity, it has naturally gained a lot of attention by developers, especially those in China.</p>
<p>A TypeScript-based library with a complete type definition, Element Plus is not based on Material Design and has its own distinct UI style which can modified quite easily. Element Plus simplifies component utilization, making the code more maintainable and readable with Vue 3's Composition API.</p>
<p>As of February 2024, Element Plus has over 22,600 stars (from 21,300 stars in 2023) on GitHub and an average weekly downloads count of over 200,000.</p>
<p>Learn more on <a target="_blank" href="https://element-plus.org/en-US/">https://element-plus.org/en-US/</a></p>
<h3 id="heading-2-ant-design-vue">2. Ant Design Vue</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727947139698/1540192a-f9b1-4810-aed3-275128f610b6.png" alt="Ant Design Vue" /></p>
<p>Ant Design Vue (Antdv) is a popular TypeScript-based UI component library based off Ant Design, a library that was developed for React and was originally created by a team from Alibaba. But it has gained traction in the Vue.js community for its ease of use and its rich feature set. It offers a comprehensive range of components like tree structures, forms, and data visualization components.</p>
<p>Similar to Element Plus, Antdv has its own unique UI style. Although it may initially seem daunting to explore its huge sets of UI components and features, once you get the hang of it, Antdv can be a very powerful UI component library for projects of all sizes.</p>
<p>As of February 2024, Ant Design Vue has over 19,300 stars (from 18,600 stars in 2023) on GitHub and an average weekly downloads count of over 80,000.</p>
<p>Learn more on <a target="_blank" href="https://antdv.com/">https://antdv.com/</a></p>
<h3 id="heading-3-naive-ui">3. Naive UI</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727947140937/3979e157-41ce-48fb-8a29-7dd3e97a06d1.png" alt="Naive UI" /></p>
<p>Naive UI is a TypeScript-based UI component library developed by TuSimple, a Chinese autonomous truck company based in California. It has been mentioned by Evan You, the creator of Vue.js, in his Weibo blog back in 2021.</p>
<p>Naive UI consists of over 90 components that can be imported to use in your project. Most impressively, all 90+ components can be <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Glossary/Tree_shaking">treeshaken</a>. This means that the component can be imported individually into your application without waste. Documentation of Naive UI is also well documented and easy to follow.</p>
<p>As of February 2024, Naive UI has over 14,800 stars on GitHub and an average weekly downloads count of over 30,000.</p>
<p>Learn more on <a target="_blank" href="https://github.com/tusen-ai/naive-ui">https://github.com/tusen-ai/naive-ui</a></p>
<h3 id="heading-special-mention-nut-ui">Special Mention: Nut UI</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727947142628/362a147b-6816-4f08-b91f-81c667e7a6e7.png" alt="Nut UI" /></p>
<p>Nut UI is a mobile UI component library that is developed by the Chinese e-commerce giant, <a target="_blank" href="http://JD.com">JD.com</a> (also known as Jingdong). It provides a JD-style mobile UI component library that is used by JD in production.</p>
<p>Nut UI features high quality UI components that are well tested (unit test coverage more than 80%). It has clear documentation and supports TypeScript. Furthermore, it provides Sketch design resources for designers to easily create design screens.</p>
<p>As of February 2024, Nut UI has over 5,700 stars on GitHub and an average weekly downloads count of over 3,000.</p>
<p>Learn more on <a target="_blank" href="https://github.com/jdf2e/nutui/blob/v4/README_EN.md">https://github.com/jdf2e/nutui/blob/v4/README_EN.md</a></p>
<hr />
<h2 id="heading-conclusion">Conclusion</h2>
<p>In conclusion, Vue.js has gained popularity due to its flexibility, simplicity, and performance. The availability of different UI component libraries has made it easier for developers to build complex and elegant applications at speed with ease. Whether you're building large complex applications or small, highly performant ones, there is always the right Vue.js UI component library suitable for your needs.</p>
<hr />
<h2 id="heading-vue-pdf-viewer-flexible-and-powerful-vuejs-pdf-component-1">Vue PDF Viewer: Flexible and Powerful Vue.js PDF Component</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727947144455/0bed84c6-91e3-460a-b88d-9c924d673472.png" alt="Vue PDF Viewer" /></p>
<p>If you feel like this article helped you, please check out <a target="_blank" href="https://www.vue-pdf-viewer.dev/?utm_source=blog&amp;utm_content=top-6-vuejs-ui-libraries-vue-3-trending-in-2024">Vue PDF Viewer</a>. You can customize the PDF viewer component to your theme, add locales, configure panel and more. Each function has TS and JS codes, unit tests and interactive demos. With our starter kits, you can start rendering the <a target="_blank" href="https://www.vue-pdf-viewer.dev/?utm_source=blog&amp;utm_content=top-6-vuejs-ui-libraries-vue-3-trending-in-2024">Vue PDF Viewer</a> in minutes.</p>
<p>It would encourage me to continue creating even more contents. Thank you in advance! 🙏</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://media.giphy.com/media/QLtO7Hs5FXtJe/giphy.gif">https://media.giphy.com/media/QLtO7Hs5FXtJe/giphy.gif</a></div>
]]></content:encoded></item><item><title><![CDATA[20++ Essential Articles for Vue.js (Vue 3) Beginner]]></title><description><![CDATA[Vue.js is a progressive JavaScript framework used for building user interfaces. It emphasizes simplicity and reactivity, making it a popular choice for web development. Vue adoption rate has been growing steadily over the past few years, with million...]]></description><link>https://blog.vue-pdf-viewer.dev/20-essential-articles-for-vuejs-vue-3-beginner</link><guid isPermaLink="true">https://blog.vue-pdf-viewer.dev/20-essential-articles-for-vuejs-vue-3-beginner</guid><category><![CDATA[Vue.js]]></category><category><![CDATA[Nuxt.js]]></category><category><![CDATA[TypeScript]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[Frontend Development]]></category><category><![CDATA[Tutorial]]></category><category><![CDATA[Beginner Developers]]></category><dc:creator><![CDATA[Anson Chieng]]></dc:creator><pubDate>Thu, 28 Sep 2023 16:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1732704425619/50457cb3-726b-4270-9d4b-d9ec3933dd0c.avif" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Vue.js is a progressive JavaScript framework used for building user interfaces. It emphasizes simplicity and reactivity, making it a popular choice for web development. Vue adoption rate has been growing steadily over the past few years, with <a target="_blank" href="https://npmtrends.com/vue">millions of weekly npm downloads</a> at this point of writing 😱</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://media.giphy.com/media/2YnutB6bmlLaX7eG89/giphy.gif">https://media.giphy.com/media/2YnutB6bmlLaX7eG89/giphy.gif</a></div>
<p> </p>
<p>According to <a target="_blank" href="https://www.jetbrains.com/lp/devecosystem-2022/javascript/">Jetbrains' State of Developer Ecosystem survey from 2017-2022</a>, Vue.js has grown to become the 2nd most popular framework used by Javascript developers. Vue.js is therefore a great choice to learn for a frontend Javascript framework.</p>
<p>If this is your first JavaScript framework, you may be feeling nervous or uncertain. So to make this journey a little bit easier, I have curated 20+ relevant articles grouped by topics to help Vue.js beginners learn the core concepts and features of Vue.js. Here are the topics to follow along:</p>
<ul>
<li><p><a class="post-section-overview" href="#introduction-to-vue-3">Introduction to Vue 3</a></p>
</li>
<li><p><a class="post-section-overview" href="#options-api-and-composition-api">Options API and Composition API</a></p>
</li>
<li><p><a class="post-section-overview" href="#vue-router">Vue Router</a></p>
</li>
<li><p><a class="post-section-overview" href="#pinia-fundamentals">Pinia Fundamentals</a></p>
</li>
<li><p><a class="post-section-overview" href="#typescript">Typescript</a></p>
</li>
<li><p><a class="post-section-overview" href="#unit-testing">Unit Testing</a></p>
</li>
</ul>
<p><em>Note: This article assumes that you have prior knowledge of JavaScript.</em></p>
<hr />
<h2 id="heading-vue-pdf-viewer-flexible-and-powerful-vuejs-pdf-component">Vue-PDF-Viewer: Flexible and Powerful Vue.js PDF Component</h2>
<p>Just a quick background about what I'm working on. <a target="_blank" href="https://www.vue-pdf-viewer.dev/?utm_source=blog&amp;utm_content=20-essential-articles-for-vuejs-vue-3-beginner">Vue-PDF-Viewer</a> renders the PDF viewer on your Vue or Nuxt websites so that your users can interact with your PDF document without leaving your sites. The component has over 20 features including theme customization, built-in localization, web responsive and more.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728271722999/e25fce91-1f6c-42ed-96ef-4f8886e80685.png" alt="Vue PDF Viewer" /></p>
<p>I would be grateful if you could check <a target="_blank" href="https://www.vue-pdf-viewer.dev/?utm_source=blog&amp;utm_content=20-essential-articles-for-vuejs-vue-3-beginner">Vue-PDF-Viewer</a> out. It will encourage me to make even more contents ❤️‍🔥</p>
<hr />
<h2 id="heading-introduction-to-vue-3">Introduction to Vue 3:</h2>
<p>Before you start coding in Vue, it is essential to gain a solid grasp of its fundamental principles and key concepts. This knowledge will grant you a deeper understanding and lay a robust groundwork for your journey into Vue development.</p>
<h3 id="heading-vuejs-part-1-to-part-5httpsdevtohiiamchrisseries24385"><a target="_blank" href="https://dev.to/hi_iam_chris/series/24385">VueJS Part 1 to Part 5</a></h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728271724773/ea62e1bc-2175-44d5-94a7-066db863e7df.png" alt="VueJS Part 1 to Part 5" /></p>
<p>This 5-part series of short articles is a good read for any beginner looking to learn Vue 3. It covers topics from the very basics, from Hello World to directives to conditional rendering and events handling.</p>
<ul>
<li><p><a target="_blank" href="https://dev.to/hi_iam_chris/vuejs-part-1-intro-to-vuejs-32cj">VueJS Part 1: Intro to VueJS</a></p>
</li>
<li><p><a target="_blank" href="https://dev.to/hi_iam_chris/vuejs-part-2-hello-vue-and-displaying-values-in-html-4eip">VueJS Part 2: Hello Vue and displaying values in HTML</a></p>
</li>
<li><p><a target="_blank" href="https://dev.to/hi_iam_chris/vuejs-part-3-vue-directives-and-conditional-rendering-4pam">VueJS part 3: Vue directives and conditional rendering</a></p>
</li>
<li><p><a target="_blank" href="https://dev.to/hi_iam_chris/vuejs-part-4-rendering-in-loop-n84">VueJS part 4: Rendering in loop</a></p>
</li>
<li><p><a target="_blank" href="https://dev.to/hi_iam_chris/vuejs-part-5-handling-events-1p2a">VueJS part 5: Handling events</a></p>
</li>
</ul>
<p>Be sure to check out all 5 parts to gain a good understanding on Vue 🎉</p>
<h3 id="heading-a-beginners-guide-to-vue-3httpswwwsitepointcomvue-3-beginner-guide"><a target="_blank" href="https://www.sitepoint.com/vue-3-beginner-guide/">A Beginner’s Guide to Vue 3</a></h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728271726191/9f10ce14-2c9d-42b0-855d-cba42774abd5.png" alt="A Beginner’s Guide to Vue 3" /></p>
<p>This article dated back in 2021 showcases examples that uses Vue CLI of an older version. However, the article still provides a great step-by-step guide in creating a simple Vue 3 app and getting to know the basic functionalities of Vue.js.</p>
<h3 id="heading-vue-made-easy-getting-started-with-vuehttpsdevtomiracoolpart-1-getting-started-with-vue-2d31"><a target="_blank" href="https://dev.to/miracool/part-1-getting-started-with-vue-2d31">Vue Made Easy: Getting Started with Vue</a></h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728271728222/1ce1e8d5-ed30-4e3e-a090-92efcff4af44.png" alt="Vue Made Easy: Getting Started with Vue" /></p>
<p>This article is part of a larger 4 parts series, and it offers a comprehensive beginner-friendly guide to getting started with Vue.js. It's easy to follow along, thanks to detailed explanations and code examples.</p>
<h3 id="heading-vuejs-for-beginners-1httpshuericnanhashnodedevvuejs-for-beginners-1"><a target="_blank" href="https://huericnan.hashnode.dev/vuejs-for-beginners-1">Vue.js for Beginners #1</a></h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728271729780/74fa0666-42d1-472a-90e7-286cc591ec8d.png" alt="Vue.js for Beginners #1" /></p>
<p>If you are looking for a clear guide with all you need to know to start developing in Vue 3, be sure to check out this 2 parts series written by Eric Hu.</p>
<ul>
<li><p><a target="_blank" href="https://huericnan.hashnode.dev/vuejs-for-beginners-1">Vue.js for Beginners #1</a></p>
</li>
<li><p><a target="_blank" href="https://huericnan.hashnode.dev/vuejs-for-beginners-2">Vue.js for Beginners #2</a></p>
</li>
</ul>
<p>In <a target="_blank" href="https://huericnan.hashnode.dev/vuejs-for-beginners-1">Part 1</a>, you will learn the very basics from installation to methods, interpolations and directives. You will also get hands on in building an app. Continue on to <a target="_blank" href="https://huericnan.hashnode.dev/vuejs-for-beginners-2">Part 2</a> to find out about event handling, forms and more!</p>
<h3 id="heading-best-practices-for-writing-vuejshttpssweetcodeiobest-practices-for-writing-vue-js"><a target="_blank" href="https://sweetcode.io/best-practices-for-writing-vue-js/">Best Practices for Writing Vue.js</a></h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728271731520/89db6f75-a63f-41d9-9dd2-d7e36ca139ff.png" alt="Best Practices for Writing Vue.js" /></p>
<p>These best practices are like a helpful guide for beginners that are starting out on Vue. They ensure your code is clean and easy to understand so that you'll not only write better code but also gain confidence as a Vue.js developer.</p>
<h3 id="heading-bonus-vue-developer-roadmaphttpsroadmapshvue">Bonus: <a target="_blank" href="https://roadmap.sh/vue">Vue Developer Roadmap</a></h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728271733100/7d2d76f8-1b60-4b37-9e74-ac75817a63f7.png" alt="Bonus - Vue Developer Roadmap" /></p>
<p>This cool looking roadmap provides a great guideline to becoming a Vue Developer. Clicking on each node will display links to useful resources for the related topic. After you are done with Vue, you can even proceed on to the Frontend developer or other roadmaps to see what you have missed on your learning journey!:sparkles:</p>
<hr />
<h2 id="heading-options-api-and-composition-api">Options API and Composition API:</h2>
<p>The Options API is a traditional way of building Vue components that has been around since 2013. However, since Composition API's release in Vue 3, it has been the preferred method that offers a more flexible and intuitive way to organize and reuse code. It allows developers to encapsulate logic into reusable functions called "composition functions."</p>
<h3 id="heading-options-api-vs-composition-apihttpsmediumcomcodexoptions-api-vs-composition-api-4a745fb8610"><a target="_blank" href="https://medium.com/codex/options-api-vs-composition-api-4a745fb8610">Options API vs. Composition API</a></h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728271734600/deffaf8e-f6a8-4dc4-b339-5163b6de3092.png" alt="Options API vs. Composition API" /></p>
<p>If you have some prior knowledge of Vue 2, chances are you may be wondering if you should use Options API. This article starts by explaining the key concepts of the Options API, such as data, methods, and lifecycle hooks. Then, it introduces the Composition API, highlighting its simplicity and reduced code size.</p>
<h3 id="heading-how-to-use-composition-api-the-right-wayhttpsdevtotheoneare-you-using-composition-api-the-right-way-4jmm"><a target="_blank" href="https://dev.to/the_one/are-you-using-composition-api-the-right-way-4jmm">How to use Composition API the right way</a></h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728271736579/4590dd72-9cf7-4992-9482-43aed2cfa337.png" alt="How to use Composition API the right way" /></p>
<p>This article further dives into the usefulness of using Composition API and the issues with Options API. It explains how to use the Composition API properly and the benefits.</p>
<h3 id="heading-why-i-love-vue-3s-composition-apihttpsdevtomokkappswhy-i-love-vue-3s-composition-api-2n3m"><a target="_blank" href="https://dev.to/mokkapps/why-i-love-vue-3s-composition-api-2n3m">Why I Love Vue 3's Composition API</a></h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728271737938/007b48b2-2571-42d1-8bdb-a75913b3aff0.png" alt="Why I Love Vue 3's Composition API" /></p>
<p>In this article, Michael Hoffman makes a clear comparison between Options API and Composition API by building the same application with each method.<br />Jump in if you want to further understand why you should be using Composition API :sunglasses:</p>
<h3 id="heading-refactoring-a-component-from-vue-2-options-api-to-vue-3-composition-apihttpsfadamakiscomfrom-vue-2-options-api-to-vue-3-composition-api-fe6d6a738c2f"><a target="_blank" href="https://fadamakis.com/from-vue-2-options-api-to-vue-3-composition-api-fe6d6a738c2f">Refactoring a Component from Vue 2 Options API to Vue 3 Composition API</a></h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728271739320/01f10e1c-0f40-40ef-a941-f3418269cd44.png" alt="Refactoring a Component from Vue 2 Options API to Vue 3 Composition API" /></p>
<p>To truly understand the Composition API, we have to first look back and understand how things work in Vue 2. In this article, it explains Options API from Vue 2 and how it evolves in Vue 3 and why Composition API should be the preferred method.<br />Great read to understand Composition API from a different perspective.</p>
<hr />
<h2 id="heading-vue-router">Vue Router</h2>
<p>Vue Router is a routing library for Vue.js that enables the creation of single-page applications. It allows developers to define routes, handle navigation, and load different components based on the current route.</p>
<h2 id="heading-how-to-use-vue-router-a-complete-tutorialhttpsvueschoolioarticlesvuejs-tutorialshow-to-use-vue-router-a-complete-tutorial"><a target="_blank" href="https://vueschool.io/articles/vuejs-tutorials/how-to-use-vue-router-a-complete-tutorial">How to Use Vue Router: A Complete Tutorial</a></h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728271741472/a5465d67-0035-499c-a3b8-5ca51d5c9bc2.png" alt="How to Use Vue Router: A Complete Tutorial" /></p>
<p>Look no further if you are looking to learn routing in Vue 3. This article covers the basics from Vue Router Fundamentals to Dynamic routing and Lazy Loading.<br />Good article to read and save for future reference!</p>
<h2 id="heading-how-to-navigate-between-views-with-vue-routerhttpswwwdigitaloceancomcommunitytutorialshow-to-navigate-between-views-with-vue-router"><a target="_blank" href="https://www.digitalocean.com/community/tutorials/how-to-navigate-between-views-with-vue-router">How To Navigate Between Views with Vue Router</a></h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728271742984/ea3dc905-3a42-49c5-9211-ff4e1b0210ad.png" alt="How To Navigate Between Views with Vue Router" /></p>
<p>Time to get hands on again! This article explains the need for Vue router and features a step-by-step guide from to build a Vue 3 application and route it with Vue router.<br />This is part of a 9 parts series with basic and advanced topics. Be sure to check them out as well</p>
<hr />
<h2 id="heading-pinia-fundamentals">Pinia Fundamentals</h2>
<p>Pinia is a state management library specifically designed for Vue.js 3. It provides a minimalistic approach to managing application state by leveraging the new features of Vue 3, including the Composition API.</p>
<h2 id="heading-easy-state-management-in-vue-3-using-piniahttpsjavascriptplainenglishiopinia-state-management-in-vue-3-d093a33d66c"><a target="_blank" href="https://javascript.plainenglish.io/pinia-state-management-in-vue-3-d093a33d66c">Easy State Management in Vue 3 Using Pinia</a></h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728271744690/e5f49882-76f9-431f-ab04-0125165ed8f2.png" alt="Easy State Management in Vue 3 Using Pinia" /></p>
<p>This short article showcases the key aspects of Pinia, the superhero of state management in Vue 3. Understand the fundamentals of Pinia and say goodbye to the confusion of passing data around :rocket:</p>
<h2 id="heading-advantages-of-pinia-vs-vuexhttpswwwvuemasterycomblogadvantages-of-pinia-vs-vuex"><a target="_blank" href="https://www.vuemastery.com/blog/advantages-of-pinia-vs-vuex/">Advantages of Pinia vs Vuex</a></h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728271746783/45c239f8-f1d5-4b1e-8220-d72331ee323c.png" alt="Advantages of Pinia vs Vuex" /></p>
<p>If you are working on state management, chances are you may be wondering to use Pinia or Vuex. And although Pinia is the recommended library for Vue.js state management, it helps to understand Vuex which is still used in Vue 3.<br />You'll find detailed Q&amp;A styled explanations to your questions here!</p>
<h2 id="heading-how-to-handle-state-management-in-vue-using-piniahttpscoderpadioblogdevelopmenthow-to-handle-state-management-in-vue-using-pinia"><a target="_blank" href="https://coderpad.io/blog/development/how-to-handle-state-management-in-vue-using-pinia">How To Handle State Management in Vue Using Pinia</a></h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728271748332/5edf9b47-b428-4e97-b0ef-58be1ad048a1.png" alt="How To Handle State Management in Vue Using Pinia" /></p>
<p>This post provides a high-level overview of handling state management in a Vue application with Pinia. It elaborates on state management and dive deeper with code examples.</p>
<hr />
<h2 id="heading-typescript">TypeScript:</h2>
<p>Vue.js 3 introduces enhanced support for TypeScript, a statically typed superset of JavaScript. TypeScript with Vue 3 improves code maintainability, type checking, and error prevention.</p>
<h2 id="heading-learn-typescript-basics-in-this-beginners-guidehttpswwwfreecodecamporgnewslearn-typescript-basics"><a target="_blank" href="https://www.freecodecamp.org/news/learn-typescript-basics/">Learn TypeScript Basics in this Beginner's Guide</a></h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728271750509/3ccb3e9f-c47c-448e-a6df-148be858ff10.png" alt="Learn TypeScript Basics in this Beginner's Guide" /></p>
<p>If you are new to TypeScript, this article is a good place to start. Although it does not relate to Vue.js, it contains information to get you started with TypeScript. It guides you through what is TypeScript, the key concepts and also all the cool features of using TypeScript :sunglasses:<br />Be sure also to check out the <a target="_blank" href="https://www.typescriptlang.org/docs/">TypeScript documentation</a>.</p>
<h2 id="heading-why-use-typescript-with-vuejshttpsvueschoolioarticlesvuejs-tutorialswhy-use-typescript-with-vue-js"><a target="_blank" href="https://vueschool.io/articles/vuejs-tutorials/why-use-typescript-with-vue-js/">Why Use TypeScript with Vue.js?</a></h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728271752447/24e8fd02-8035-4d7b-879e-294df38954d4.png" alt="Why Use TypeScript with Vue.js?" /></p>
<p>Need more convincing to start using TypeScript with Vue 3? Check this article out for more insights on using TypeScript in your Vue.js project.</p>
<h2 id="heading-getting-started-with-vuejs3-and-typescript-a-beginners-guidehttpsearnkayhashnodedevgetting-started-with-vuejs3-and-typescript-a-beginners-guide"><a target="_blank" href="https://earnkay.hashnode.dev/getting-started-with-vuejs3-and-typescript-a-beginners-guide">Getting started with Vue.js3 and Typescript: A Beginners Guide</a></h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728271754135/0ba75f31-1d69-46fe-8514-2812db089175.png" alt="Getting started with Vue.js3 and Typescript: A Beginners Guide" /></p>
<p>Now that you know TypeScript, it's time to dive in. Learn how to set up your project, create components, and effortlessly bind data for dynamic user interfaces 🌟</p>
<hr />
<h2 id="heading-unit-testing">Unit Testing:</h2>
<p>Unit testing plays a crucial role in ensuring the quality and reliability of Vue.js applications. Unit testing can be implemented via popular testing frameworks and libraries such as Jest, Vite and Vue Test Utils.</p>
<h2 id="heading-testing-vuejs-components-with-vue-test-utilshttpsstackabusecomtesting-vue-js-components-with-vue-test-utils"><a target="_blank" href="https://stackabuse.com/testing-vue-js-components-with-vue-test-utils">Testing Vue.js Components with Vue Test Utils</a></h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728271755453/f88cd9a6-69a3-4be7-bfff-e0b60ff7c171.png" alt="Testing Vue.js Components with Vue Test Utils" /></p>
<p>Vue 3 provides an official set of testing utilities known as Vue Test Utils. This article walks you through using Vue Test Utils and Jest to write unit tests. It provides examples to test your Vue.js codes and components such as forms and emitted events.</p>
<h2 id="heading-getting-started-with-vitesthttpsmediumcomvue-masterygetting-started-with-vitest-4897d153b41f"><a target="_blank" href="https://medium.com/vue-mastery/getting-started-with-vitest-4897d153b41f">Getting Started with Vitest</a></h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728271757178/b62c716c-8927-4c01-af85-6ee75275e3ac.png" alt="Getting Started with Vitest" /></p>
<p>If you are already running your Vue.js projects with Vite, a build tool developed by Evan You, consider using the blazing fast Vitest for your tests instead :fire: Get started by following the installation instructions and demos in this article.</p>
<h2 id="heading-knowing-what-to-test-vue-component-unit-testinghttpsvuejsdeveloperscom20190826vue-what-to-unit-test-components"><a target="_blank" href="https://vuejsdevelopers.com/2019/08/26/vue-what-to-unit-test-components/">Knowing What To Test - Vue Component Unit Testing</a></h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728271758640/e2e33215-78c8-47b3-aad9-505df43ad566.png" alt="Knowing What To Test - Vue Component Unit Testing" /></p>
<p>Learning the tools to unit testing is important, however it is just as crucial to know what to test. As a beginner, you may feel lost at first which components to test. Understanding this will save you time and effort in testing only the key components and business logics.<br />Although the codes in this article is written in Vue 2, it is still a good read that provides valuable insights to unit testing.</p>
<hr />
<h2 id="heading-conclusion">Conclusion</h2>
<p>In the world of Vue.js 3, we've rounded up 21 articles that are pretty handy for beginners. These articles cover a bunch of stuff, from the basics of Vue.js to Composition API, Vue Router, Pinia, TypeScript, and unit testing. Whether you're just starting out or want to level up your Vue.js skills, these articles have got you covered. Vue.js is becoming more and more popular, so these resources will help you build web apps with ease. Dive into these articles and become a Vue.js whiz at your own pace! 🚀</p>
<hr />
<h2 id="heading-vue-pdf-viewer-flexible-and-powerful-vuejs-pdf-component-1">Vue-PDF-Viewer: Flexible and Powerful Vue.js PDF Component</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728271760190/eba971f4-9e1a-464a-956e-61a95b0f4792.png" alt="Vue PDF Viewer" /></p>
<p>If you feel like this article helped you, please check out <a target="_blank" href="https://www.vue-pdf-viewer.dev/?utm_source=blog&amp;utm_content=20-essential-articles-for-vuejs-vue-3-beginner">Vue-PDF-Viewer</a>. You can customize the PDF viewer component to your theme, add locales, configure panel and more. Each function has TS and JS codes, unit tests and interactive demos. With our starter kits, you can start rendering the <a target="_blank" href="https://www.vue-pdf-viewer.dev/?utm_source=blog&amp;utm_content=20-essential-articles-for-vuejs-vue-3-beginner">Vue-PDF-Viewer</a> in minutes.</p>
<p>It would encourage me to continue creating even more contents. Thank you in advance! 🙏</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://media.giphy.com/media/4ml290TZ35zOM/giphy.gif?cid=790b7611zbf2ry04gh694yqhg5ys82s7j2b3xlcxttgshcyz&amp;ep=v1_gifs_search&amp;rid=giphy.gif&amp;ct=g">https://media.giphy.com/media/4ml290TZ35zOM/giphy.gif?cid=790b7611zbf2ry04gh694yqhg5ys82s7j2b3xlcxttgshcyz&amp;ep=v1_gifs_search&amp;rid=giphy.gif&amp;ct=g</a></div>
]]></content:encoded></item><item><title><![CDATA[🤔 3 Major Problems of Reusable Components in Vue.js 🔥]]></title><description><![CDATA[When we talk or discuss about creating UI components in Vue.js, reusability is often brought up. Yes, one of the key principles of Vue.js is its component-based architecture, which promotes reusability and modularity. But what does that even mean?
Le...]]></description><link>https://blog.vue-pdf-viewer.dev/3-major-problems-of-reusable-components-in-vuejs</link><guid isPermaLink="true">https://blog.vue-pdf-viewer.dev/3-major-problems-of-reusable-components-in-vuejs</guid><category><![CDATA[Vue.js]]></category><category><![CDATA[Nuxt]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[TypeScript]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[Frontend Development]]></category><dc:creator><![CDATA[watcharakorn]]></dc:creator><pubDate>Sun, 17 Sep 2023 16:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1728350103227/89e44bc2-3ea5-4c0d-b8d2-ba9bb356e5df.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When we talk or discuss about creating UI components in Vue.js, reusability is often brought up. Yes, one of the key principles of Vue.js is its component-based architecture, which promotes reusability and modularity. But what does that even mean?</p>
<p>Let's say you create a reusable component:</p>
<ul>
<li><p>Can you or your colleagues really reuse (no pun intended) it in another part of the system?</p>
</li>
<li><p>With a new requirement, you may have to consider modifying the "reusable component".</p>
</li>
<li><p>What if you need to split the "reusable component" to so that you can apply the split component to another place?</p>
</li>
</ul>
<p><img src="https://media.giphy.com/media/6HNonYwCD4yrHFk7ya/giphy.gif" alt class="image--center mx-auto" /></p>
<p>Creating actually reusable components in Vue.js can be tricky. In this article, I will explore the concept of reusable components, the problems faced when applying them, and why it is essential to overcome these problems as best as I can.</p>
<hr />
<h2 id="heading-vue-pdf-viewer-flexible-and-powerful-vuejs-pdf-component">Vue-PDF-Viewer: Flexible and Powerful Vue.js PDF Component</h2>
<p>Just a quick background about what I’m working on. <a target="_blank" href="https://www.vue-pdf-viewer.dev/?utm_source=blog&amp;utm_content=3-major-problems-of-reusable-components-in-vuejs">Vue-PDF-Viewer</a> renders the PDF viewer on your Vue or Nuxt websites so that your users can interact with your PDF document without leaving your sites. The component has over 20 features including theme customization, built-in localization, web responsive and more.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727947131835/59fe35c4-93e4-4cef-9e79-88fd84d5fc7f.png" alt="Vue PDF Viewer" /></p>
<p>I would be grateful if you could check <a target="_blank" href="https://www.vue-pdf-viewer.dev/?utm_source=blog&amp;utm_content=3-major-problems-of-reusable-components-in-vuejs">Vue-PDF-Viewer</a> out. It will encourage me to make even more contents 🎉</p>
<hr />
<h2 id="heading-what-are-reusable-components">What are Reusable Components?</h2>
<p>Reusable components are UI building blocks that can be used in different parts of an application or even across multiple projects. They encapsulate specific functionality or UI patterns and can be easily integrated into other parts of the application without the need for extensive modifications.</p>
<h2 id="heading-benefits-of-reusable-components">Benefits of Reusable Components</h2>
<p>By using Reusable Components in Vue.js, you can achieve several benefits like:</p>
<ul>
<li><p><strong>Efficiency</strong>: Allow developers to write code once and reuse it multiple times. This reduces redundancy and saves valuable development time.</p>
</li>
<li><p><strong>Standardization</strong>: Promote consistency and standardization across a Vue.js project. They ensure that the same design patterns, styles, and functionality are maintained throughout the application.</p>
</li>
<li><p><strong>Scalability</strong>: Make it easier to scale and adapt projects as they grow. By breaking down the application into smaller, reusable components, it becomes more manageable to handle complex functionalities and add new features.</p>
</li>
<li><p><strong>Collaboration</strong>: Facilitate collaboration among team members working on a Vue.js project. They provide a shared vocabulary and set of UI elements that everyone in the team can use and understand.</p>
</li>
</ul>
<hr />
<h2 id="heading-3-problems-when-applying-reusable-concept">3 Problems when Applying Reusable Concept</h2>
<p>While reusability is a desirable trait in Vue.js components, several problems can make it difficult to achieve:</p>
<ol>
<li><p><strong>Modifying Existing Components</strong>: One problem is modifying existing components that are already being used in the application. The component may need to be changed to support both existing and new requirements. Making changes to a component that is already used in other parts of the application may introduce unintended side effects and break functionality in other areas. Balancing the need for changes with maintaining compatibility can be complex.</p>
</li>
<li><p><strong>Design Components for Consistency and Flexibility</strong>: Another problem is maintaining consistency across different instances of a reusable component while allowing for customization and flexibility. Reusable components should be versatile enough to adapt to different design requirements and styles. However, providing customization options without sacrificing the core functionality and consistency of the component can be tricky.</p>
</li>
<li><p><strong>Managing Component Dependencies and State</strong>: Using reusable components involves managing dependencies and ensuring that each component remains self-contained and independent. Components should not have tight dependencies on external resources or the application's state management system. This allows for easy integration into different projects and reduces the likelihood of conflicts or unintended side effects.</p>
</li>
</ol>
<hr />
<h2 id="heading-a-case-study">A Case Study</h2>
<p>Let's say, a client wants an internal employee directory system. The project is engaged based on Agile methodology and all requirements cannot be gathered before development. There are 3 phases (Prototype, Phase 1 and Phase 2). For the purpose of this demonstration, I will focus on a card component like below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728285223564/6875ba11-2df6-475f-bf65-0edf26611d70.gif" alt="User card component and tooltip component" /></p>
<h3 id="heading-prototype">Prototype</h3>
<p>As part of the prototype phase, I am required to deliver a User Profile page. The user profile will contain a basic user card component to include user avatar and name.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728285225326/a2229706-dfc8-4e49-8724-bf8a6b8d3de3.png" alt="basic user card component" /></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Prototype.vue</span>
&lt;script setup lang=<span class="hljs-string">"ts"</span>&gt;
    <span class="hljs-keyword">import</span> { defineProps, computed, Teleport, ref } <span class="hljs-keyword">from</span> <span class="hljs-string">"vue"</span>;

    <span class="hljs-keyword">interface</span> Props {
        firstName: <span class="hljs-built_in">string</span>;
        lastName: <span class="hljs-built_in">string</span>;
        image?: <span class="hljs-built_in">string</span>;
    }

    <span class="hljs-keyword">const</span> props = defineProps&lt;Props&gt;();
&lt;/script&gt;

&lt;template&gt;
    &lt;div <span class="hljs-keyword">class</span>=<span class="hljs-string">"app-card"</span>&gt;
        &lt;img
            <span class="hljs-keyword">class</span>=<span class="hljs-string">"user-image"</span>
            :src=<span class="hljs-string">"image"</span>
            alt=<span class="hljs-string">"avatar"</span> /&gt;
        &lt;div&gt;
            &lt;div&gt;
                &lt;label&gt; {{ firstName }} {{ lastName }} &lt;/label&gt;
            &lt;/div&gt;
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/template&gt;

&lt;style scoped&gt;
    .app-card {
        padding-left: <span class="hljs-number">10</span>px;
        padding-right: <span class="hljs-number">10</span>px;
        padding-top: <span class="hljs-number">5</span>px;
        padding-bottom: <span class="hljs-number">5</span>px;
        background: white;
        box-shadow: <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">5</span>px;
        border-radius: <span class="hljs-number">5</span>px;
        border: none;
        font-size: <span class="hljs-number">1.5</span>em;
        transition: <span class="hljs-number">0.3</span>s;
        display: flex;
        align-items: center;
    }
    .app-card label {
        font-weight: <span class="hljs-number">600</span>;
    }
    .app-card:hover {
        background: rgba(<span class="hljs-number">128</span>, <span class="hljs-number">128</span>, <span class="hljs-number">128</span>, <span class="hljs-number">0.5</span>);
    }
    .user-image {
        width: <span class="hljs-number">100</span>px;
    }
&lt;/style&gt;
</code></pre>
<h3 id="heading-phase-1">Phase 1</h3>
<p>In Phase 1, the client wants to add user detail (birthday, age, phone number and email) onto the user card component.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728285226521/069cab84-fa6b-47d1-8860-2aff02c6dbf2.png" alt="user card component with user detail" /></p>
<pre><code class="lang-typescript"><span class="hljs-comment">//Phase1.vue</span>
&lt;script setup lang=<span class="hljs-string">"ts"</span>&gt;
    <span class="hljs-keyword">import</span> { defineProps, computed } <span class="hljs-keyword">from</span> <span class="hljs-string">"vue"</span>;

    <span class="hljs-keyword">interface</span> Props {
        firstName: <span class="hljs-built_in">string</span>;
        lastName: <span class="hljs-built_in">string</span>;
        image?: <span class="hljs-built_in">string</span>;
        birthDay?: <span class="hljs-built_in">string</span>;
        phone?: <span class="hljs-built_in">string</span>;
        email?: <span class="hljs-built_in">string</span>;
    }

    <span class="hljs-keyword">const</span> props = defineProps&lt;Props&gt;();

    <span class="hljs-keyword">const</span> age = computed(<span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">if</span> (!props.birthDay) {
            <span class="hljs-keyword">return</span> <span class="hljs-string">"0"</span>;
        }
        <span class="hljs-keyword">const</span> birthYear = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(props.birthDay).getFullYear();
        <span class="hljs-keyword">const</span> currentYear = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().getFullYear();
        <span class="hljs-keyword">return</span> currentYear - birthYear;
    });
&lt;/script&gt;

&lt;template&gt;
    &lt;div
        ref=<span class="hljs-string">"cardRef"</span>
        <span class="hljs-keyword">class</span>=<span class="hljs-string">"app-card"</span>&gt;
        &lt;img
            <span class="hljs-keyword">class</span>=<span class="hljs-string">"user-image"</span>
            :src=<span class="hljs-string">"image"</span>
            alt=<span class="hljs-string">"avatar"</span> /&gt;
        &lt;div&gt;
            &lt;div&gt;
                &lt;label&gt; {{ firstName }} {{ lastName }} &lt;/label&gt;
            &lt;/div&gt;
            &lt;div&gt;
                &lt;div&gt;
                    &lt;label&gt; Birth day: &lt;/label&gt;
                    &lt;span&gt;
                        {{ birthDay }}
                    &lt;/span&gt;
                &lt;/div&gt;
                &lt;div&gt;
                    &lt;label&gt; Age: &lt;/label&gt;
                    &lt;span&gt;
                        {{ age }}
                    &lt;/span&gt;
                &lt;/div&gt;
                &lt;div&gt;
                    &lt;label&gt; Phone <span class="hljs-built_in">number</span>: &lt;/label&gt;
                    &lt;span&gt;
                        {{ phone }}
                    &lt;/span&gt;
                &lt;/div&gt;
                &lt;div&gt;
                    &lt;label&gt; Email: &lt;/label&gt;
                    &lt;span&gt;
                        {{ email }}
                    &lt;/span&gt;
                &lt;/div&gt;
            &lt;/div&gt;
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/template&gt;

&lt;style scoped&gt;
    .app-card {
        padding-left: <span class="hljs-number">10</span>px;
        padding-right: <span class="hljs-number">10</span>px;
        padding-top: <span class="hljs-number">5</span>px;
        padding-bottom: <span class="hljs-number">5</span>px;
        background: white;
        box-shadow: <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">5</span>px;
        border-radius: <span class="hljs-number">5</span>px;
        border: none;
        font-size: <span class="hljs-number">1.5</span>em;
        transition: <span class="hljs-number">0.3</span>s;
        display: flex;
        align-items: center;
    }
    .app-card label {
        font-weight: <span class="hljs-number">600</span>;
    }
    .app-card:hover {
        background: rgba(<span class="hljs-number">128</span>, <span class="hljs-number">128</span>, <span class="hljs-number">128</span>, <span class="hljs-number">0.5</span>);
        color: black;
    }
    .user-image {
        width: <span class="hljs-number">100</span>px;
    }
&lt;/style&gt;
</code></pre>
<p>Additionally, the client is looking to add Employee Directory page and display user profiles in a card format.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728285228200/99142ee9-684b-4536-af83-503576fd0dfb.gif" alt="search for user profile" /></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// SearchPage</span>
&lt;template&gt;
    &lt;div&gt;
        &lt;SearchInput v-model:value=<span class="hljs-string">"searchValue"</span> /&gt;
        &lt;template
            :key=<span class="hljs-string">"item.id"</span>
            v-<span class="hljs-keyword">for</span>=<span class="hljs-string">"item of list"</span>&gt;
            &lt;div style=<span class="hljs-string">"margin-bottom: 5px; margin-top: 5px"</span>&gt;
                &lt;UserCard v-bind=<span class="hljs-string">"item"</span> /&gt;
            &lt;/div&gt;
        &lt;/template&gt;
    &lt;/div&gt;
&lt;/template&gt;

&lt;script lang=<span class="hljs-string">"ts"</span>&gt;
    <span class="hljs-keyword">import</span> SearchInput <span class="hljs-keyword">from</span> <span class="hljs-string">"../components/SearchInput.vue"</span>;
    <span class="hljs-keyword">import</span> UserCard <span class="hljs-keyword">from</span> <span class="hljs-string">"../components/Phase1.vue"</span>;
    <span class="hljs-keyword">import</span> { ref, watch } <span class="hljs-keyword">from</span> <span class="hljs-string">"vue"</span>;

    <span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
        name: <span class="hljs-string">"Search"</span>,
        components: {
            SearchInput,
            UserCard,
        },
        setup() {
            <span class="hljs-keyword">const</span> searchValue = ref&lt;<span class="hljs-built_in">string</span>&gt;();
            <span class="hljs-keyword">const</span> list = ref();
            fetch(<span class="hljs-string">"https://dummyjson.com/users"</span>)
                .then(<span class="hljs-function">(<span class="hljs-params">res</span>) =&gt;</span> res.json())
                .then(<span class="hljs-function">(<span class="hljs-params">res</span>) =&gt;</span> (list.value = res.users));

            watch(searchValue, <span class="hljs-function">(<span class="hljs-params">v</span>) =&gt;</span> {
                fetch(<span class="hljs-string">`https://dummyjson.com/users/search?q=<span class="hljs-subst">${v}</span>`</span>)
                    .then(<span class="hljs-function">(<span class="hljs-params">res</span>) =&gt;</span> res.json())
                    .then(<span class="hljs-function">(<span class="hljs-params">res</span>) =&gt;</span> (list.value = res.users));
            });

            watch(list, <span class="hljs-function">(<span class="hljs-params">v</span>) =&gt;</span> <span class="hljs-built_in">console</span>.log(v));

            <span class="hljs-keyword">return</span> {
                searchValue,
                list,
            };
        },
    };
&lt;/script&gt;
</code></pre>
<p>At this stage, the user card component is reusable on both pages.</p>
<h3 id="heading-phase-2">Phase 2</h3>
<p>Users feedback that the Employee Directory page is cluttered. Too much information making the page hard to use. Therefore, the client wants the user detail to be shown in tooltip upon hovered. The requirement on the User Setting page remains unchanged.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728285230058/9c340d6f-215d-4237-973f-fda0176670cc.gif" alt="user card component and tooltip component" /></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Phase 2</span>
&lt;script setup lang=<span class="hljs-string">"ts"</span>&gt;
<span class="hljs-keyword">import</span> {
  defineProps,
  computed,
  Teleport,
  ref,
  onMounted,
  onBeforeUnmount,
} <span class="hljs-keyword">from</span> <span class="hljs-string">"vue"</span>;

<span class="hljs-keyword">interface</span> Props {
  firstName: <span class="hljs-built_in">string</span>;
  lastName: <span class="hljs-built_in">string</span>;
  image?: <span class="hljs-built_in">string</span>;
  birthDate?: <span class="hljs-built_in">string</span>;
  phone?: <span class="hljs-built_in">string</span>;
  email?: <span class="hljs-built_in">string</span>;
  address?: <span class="hljs-built_in">string</span>;
}

<span class="hljs-keyword">const</span> props = defineProps&lt;Props&gt;();

<span class="hljs-keyword">const</span> targetRef = ref&lt;HTMLDiveElement&gt;();
<span class="hljs-keyword">const</span> isMouseOver = ref(<span class="hljs-literal">false</span>);
<span class="hljs-keyword">const</span> dropdownRef = ref&lt;HTMLDivElement&gt;();
<span class="hljs-keyword">const</span> dropdownStyle = ref({});

<span class="hljs-comment">// add modal element in body to prevent overflow issue</span>
<span class="hljs-keyword">const</span> modalElement = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"div"</span>);
modalElement.id = <span class="hljs-string">"modal"</span>;
<span class="hljs-built_in">document</span>.body.appendChild(modalElement);

<span class="hljs-keyword">const</span> age = computed(<span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">if</span> (!props.birthDate) {
    <span class="hljs-keyword">return</span> <span class="hljs-string">"0"</span>;
  }
  <span class="hljs-keyword">const</span> birthYear = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(props.birthDate).getFullYear();
  <span class="hljs-keyword">const</span> currentYear = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().getFullYear();
  <span class="hljs-keyword">return</span> currentYear - birthYear;
});

<span class="hljs-keyword">const</span> onMouseOver = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">if</span> (isMouseOver.value) {
    <span class="hljs-keyword">return</span>;
  }
  isMouseOver.value = <span class="hljs-literal">true</span>;
  <span class="hljs-keyword">const</span> dimension = targetRef.value.getBoundingClientRect();
  dropdownStyle.value = {
    width: <span class="hljs-string">`<span class="hljs-subst">${dimension.width}</span>px`</span>,
    left: <span class="hljs-string">`<span class="hljs-subst">${dimension.x}</span>px`</span>,
    top: <span class="hljs-string">`<span class="hljs-subst">${<span class="hljs-built_in">window</span>.scrollY + dimension.y + dimension.height + <span class="hljs-number">5</span>}</span>px`</span>,
  };
};

<span class="hljs-keyword">const</span> onMouseLeave = <span class="hljs-function">() =&gt;</span> {
  isMouseOver.value = <span class="hljs-literal">false</span>;
};
&lt;/script&gt;

&lt;template&gt;
  &lt;div
    ref=<span class="hljs-string">"targetRef"</span>
    <span class="hljs-meta">@mouseover</span>=<span class="hljs-string">"onMouseOver"</span>
    <span class="hljs-meta">@mouseleave</span>=<span class="hljs-string">"onMouseLeave"</span>
    <span class="hljs-keyword">class</span>=<span class="hljs-string">"app-card"</span>
  &gt;
    &lt;img <span class="hljs-keyword">class</span>=<span class="hljs-string">"user-image"</span> :src=<span class="hljs-string">"image"</span> alt=<span class="hljs-string">"avatar"</span> /&gt;
    &lt;div&gt;
      &lt;div&gt;
        &lt;label&gt; {{ firstName }} {{ lastName }} &lt;/label&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  &lt;Teleport to=<span class="hljs-string">"#modal"</span>&gt;
    &lt;div
      ref=<span class="hljs-string">"dropdownRef"</span>
      :style=<span class="hljs-string">"dropdownStyle"</span>
      style=<span class="hljs-string">"position: absolute"</span>
      v-show=<span class="hljs-string">"isMouseOver"</span>
    &gt;
      &lt;div <span class="hljs-keyword">class</span>=<span class="hljs-string">"app-card"</span>&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;label&gt; Birth day: &lt;/label&gt;
            &lt;span&gt;
              {{ birthDate }}
            &lt;/span&gt;
          &lt;/div&gt;
          &lt;div&gt;
            &lt;label&gt; Age: &lt;/label&gt;
            &lt;span&gt;
              {{ age }}
            &lt;/span&gt;
          &lt;/div&gt;
          &lt;div&gt;
            &lt;label&gt; Phone <span class="hljs-built_in">number</span>: &lt;/label&gt;
            &lt;span&gt;
              {{ phone }}
            &lt;/span&gt;
          &lt;/div&gt;
          &lt;div&gt;
            &lt;label&gt; Email: &lt;/label&gt;
            &lt;span&gt;
              {{ email }}
            &lt;/span&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/Teleport&gt;
&lt;/template&gt;

&lt;style scoped&gt;
.app-card {
  padding-left: <span class="hljs-number">10</span>px;
  padding-right: <span class="hljs-number">10</span>px;
  padding-top: <span class="hljs-number">5</span>px;
  padding-bottom: <span class="hljs-number">5</span>px;
  background: white;
  box-shadow: <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">5</span>px;
  border-radius: <span class="hljs-number">5</span>px;
  border: none;
  font-size: <span class="hljs-number">1.5</span>em;
  transition: <span class="hljs-number">0.3</span>s;
  display: flex;
  align-items: center;
}
.app-card label {
  font-weight: <span class="hljs-number">600</span>;
}
.app-card:hover {
  background: rgba(<span class="hljs-number">128</span>, <span class="hljs-number">128</span>, <span class="hljs-number">128</span>, <span class="hljs-number">0.5</span>);
  color: black;
}
.user-image {
  width: <span class="hljs-number">100</span>px;
}
&lt;/style&gt;
</code></pre>
<p>To look at the codes of Prototype, Phase 1 and Phase 2, you can find them in <a target="_blank" href="https://codesandbox.io/s/reusable-components-in-vue-wwsd5y?file=/src/components/Prototype.vue">live demo</a>.</p>
<p>This new requirement causes a headache:</p>
<ul>
<li><p>Do I modify the existing user card component to support the tooltip requirement and risk affecting the user card component in the User Setting page? OR</p>
</li>
<li><p>Do I duplicate the existing user card component and add tooltip feature?</p>
</li>
</ul>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://media.giphy.com/media/rJVShwlm8uy9msUfhY/giphy.gif?cid=790b7611tkv8beis8iu1owfj1bxjujtsstyppxb54kbpq3gi&amp;ep=v1_gifs_search&amp;rid=giphy.gif&amp;ct=g">https://media.giphy.com/media/rJVShwlm8uy9msUfhY/giphy.gif?cid=790b7611tkv8beis8iu1owfj1bxjujtsstyppxb54kbpq3gi&amp;ep=v1_gifs_search&amp;rid=giphy.gif&amp;ct=g</a></div>
<p> </p>
<p>Because we do not want to break what is already in production, we tend to choose the latter option. At first, this may make sense but it can be quite damaging, especially for big and continuous projects:</p>
<ol>
<li><p><strong>Large Codebase</strong>: Leads to a larger codebase, as each duplicated component adds unnecessary lines of code. Become difficult to maintain, as developers need to make changes in multiple places whenever an update or bug fix is required. It also increases the chances of inconsistencies.</p>
</li>
<li><p><strong>Short Term Gain, Long Term Pain</strong>: Seem like a quick and easy solution in the short term, especially when dealing with tight deadlines or urgent requirements. However, as your project grows, maintaining duplicated components becomes increasingly difficult and time-consuming. Modifications or updates to duplicated components need to be replicated across multiple instances, leading to a higher chance of errors.</p>
</li>
<li><p><strong>System Performance</strong>: Can negatively impact system performance. Redundant code increases the size of the application, leading to slower rendering times and increased memory usage. This can result in a suboptimal user experience and reduced system efficiency.</p>
</li>
</ol>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExenB3cG1kaWlmZWozZ3FoaTA0eGdmMmo3OTE1NTQ3YXpscWtzcWh5MSZlcD12MV9naWZzX3NlYXJjaCZjdD1n/S79NL9AGw9Cye65fhn/giphy.gif">https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExenB3cG1kaWlmZWozZ3FoaTA0eGdmMmo3OTE1NTQ3YXpscWtzcWh5MSZlcD12MV9naWZzX3NlYXJjaCZjdD1n/S79NL9AGw9Cye65fhn/giphy.gif</a></div>
<p> </p>
<hr />
<h2 id="heading-how-to-overcome-the-above-problems">How to Overcome the Above Problems</h2>
<p>It's to be mentally prepared that the reusable components may not always remain the same throughout your project. It may sound cliche but if you think about it, requirements are always evolving. You cannot control the future except do the best you can at the moment. Of course, experiences help you designing better components but it takes time.</p>
<h3 id="heading-refactor-reusable-components">Refactor Reusable Components</h3>
<p>From my experience, I will redesign and refactor the reusable components. Refactoring is a process to restructure codes, while not changing its original functionality. I'm sure there are many ways to refactor and, for me, I refactor and breakdown the components into smaller components. Smaller components allow for flexibility in applying them across the system. Let's take a look how I will apply the case study mentioned above.</p>
<p><em>Note: It takes discipline to refactoring UI components. Also, it can be challenging at times since you will need to balance with project delivery deadlines and cleaner codes.</em></p>
<h4 id="heading-apply-solution-to-the-case-study">Apply Solution to the Case Study</h4>
<p>First, I will split the existing user card components into 4 components:</p>
<ul>
<li><p>Card component</p>
</li>
<li><p>Avatar component</p>
</li>
<li><p>Name component</p>
</li>
<li><p>User detail component</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728285231399/57df37c8-5c5c-4af3-a0ab-e0f78f3bb738.png" alt="card, avatar, name and user detail components" /></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Card.vue</span>
&lt;template&gt;
    &lt;div <span class="hljs-keyword">class</span>=<span class="hljs-string">"app-card"</span>&gt;
        &lt;slot&gt;&lt;/slot&gt;
    &lt;/div&gt;
&lt;/template&gt;

&lt;style scoped&gt;
    .app-card {
        padding-left: <span class="hljs-number">15</span>px;
        padding-right: <span class="hljs-number">15</span>px;
        padding-top: <span class="hljs-number">10</span>px;
        padding-bottom: <span class="hljs-number">10</span>px;
        border-radius: <span class="hljs-number">5</span>px;
        border: none;
        background: white;
        color: black;
        font-size: <span class="hljs-number">1.5</span>em;
        transition: <span class="hljs-number">0.3</span>s;
        display: flex;
        align-items: center;
        box-shadow: <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">5</span>px;
    }
    .app-card:hover {
        background: rgba(<span class="hljs-number">128</span>, <span class="hljs-number">128</span>, <span class="hljs-number">128</span>, <span class="hljs-number">0.5</span>);
        color: black;
    }
&lt;/style&gt;
</code></pre>
<pre><code class="lang-typescript"><span class="hljs-comment">// Avatar.vue</span>
&lt;script setup lang=<span class="hljs-string">"ts"</span>&gt;
    <span class="hljs-keyword">import</span> { defineProps } <span class="hljs-keyword">from</span> <span class="hljs-string">"vue"</span>;

    <span class="hljs-keyword">interface</span> Props {
        image: <span class="hljs-built_in">string</span>;
    }

    <span class="hljs-keyword">const</span> props = defineProps&lt;Props&gt;();
&lt;/script&gt;

&lt;template&gt;
    &lt;img
        <span class="hljs-keyword">class</span>=<span class="hljs-string">"user-image"</span>
        :src=<span class="hljs-string">"image"</span>
        alt=<span class="hljs-string">"avatar"</span> /&gt;
&lt;/template&gt;

&lt;style scoped&gt;
    .user-image {
        width: <span class="hljs-number">100</span>px;
    }
&lt;/style&gt;
</code></pre>
<pre><code class="lang-typescript"><span class="hljs-comment">// UserName.vue</span>
&lt;script setup lang=<span class="hljs-string">"ts"</span>&gt;
    <span class="hljs-keyword">import</span> { defineProps } <span class="hljs-keyword">from</span> <span class="hljs-string">"vue"</span>;

    <span class="hljs-keyword">interface</span> Props {
        firstName: <span class="hljs-built_in">string</span>;
        lastName: <span class="hljs-built_in">string</span>;
    }

    <span class="hljs-keyword">const</span> props = defineProps&lt;Props&gt;();
&lt;/script&gt;

&lt;template&gt;
    &lt;label&gt; {{ firstName }} {{ lastName }} &lt;/label&gt;
&lt;/template&gt;
</code></pre>
<pre><code class="lang-typescript"><span class="hljs-comment">// Description Item</span>
&lt;script setup lang=<span class="hljs-string">"ts"</span>&gt;
    <span class="hljs-keyword">import</span> { defineProps } <span class="hljs-keyword">from</span> <span class="hljs-string">"vue"</span>;

    <span class="hljs-keyword">interface</span> Props {
        label: <span class="hljs-built_in">string</span>;
        value: <span class="hljs-built_in">string</span> | <span class="hljs-built_in">number</span>;
    }

    <span class="hljs-keyword">const</span> props = defineProps&lt;Props&gt;();
&lt;/script&gt;

&lt;template&gt;
    &lt;div&gt;
        &lt;label&gt; {{ label }}: &lt;/label&gt;
        &lt;span&gt;
            {{ value }}
        &lt;/span&gt;
    &lt;/div&gt;
&lt;/template&gt;

&lt;style scoped&gt;
    label {
        font-weight: <span class="hljs-number">600</span>;
    }
&lt;/style&gt;
</code></pre>
<pre><code class="lang-typescript"><span class="hljs-comment">// UserDescription.vue</span>
&lt;script setup lang=<span class="hljs-string">"ts"</span>&gt;
    <span class="hljs-keyword">import</span> DescriptionItem <span class="hljs-keyword">from</span> <span class="hljs-string">"./DescriptionItem.vue"</span>;
    <span class="hljs-keyword">import</span> { defineProps, computed } <span class="hljs-keyword">from</span> <span class="hljs-string">"vue"</span>;

    <span class="hljs-keyword">interface</span> Props {
        birthDate: <span class="hljs-built_in">string</span>;
        phone: <span class="hljs-built_in">string</span>;
        email: <span class="hljs-built_in">string</span>;
    }

    <span class="hljs-keyword">const</span> props = defineProps&lt;Props&gt;();

    <span class="hljs-keyword">const</span> age = computed(<span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">if</span> (!props.birthDate) {
            <span class="hljs-keyword">return</span> <span class="hljs-string">"0"</span>;
        }
        <span class="hljs-keyword">const</span> birthYear = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(props.birthDate).getFullYear();
        <span class="hljs-keyword">const</span> currentYear = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().getFullYear();
        <span class="hljs-keyword">return</span> currentYear - birthYear;
    });
&lt;/script&gt;

&lt;template&gt;
    &lt;div&gt;
        &lt;DescriptionItem
            label=<span class="hljs-string">"Birth day"</span>
            :value=<span class="hljs-string">"birthDate"</span> /&gt;
        &lt;DescriptionItem
            label=<span class="hljs-string">"Age"</span>
            :value=<span class="hljs-string">"age"</span> /&gt;
        &lt;DescriptionItem
            label=<span class="hljs-string">"Phone number"</span>
            :value=<span class="hljs-string">"phone"</span> /&gt;
        &lt;DescriptionItem
            label=<span class="hljs-string">"Email"</span>
            :value=<span class="hljs-string">"email"</span> /&gt;
    &lt;/div&gt;
&lt;/template&gt;
</code></pre>
<p>After that, I will create a tooltip component. Creating a separate tooltip allows me to reuse it in other parts of the system.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728285232508/68a8b172-10a7-45eb-aa15-af7deced175b.png" alt="tooltip component" /></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Tooltip.vue</span>
&lt;script setup lang=<span class="hljs-string">"ts"</span>&gt;
<span class="hljs-keyword">import</span> {
  Teleport,
  computed,
  ref,
  onMounted,
  onBeforeUnmount,
  watch,
} <span class="hljs-keyword">from</span> <span class="hljs-string">"vue"</span>;

<span class="hljs-keyword">const</span> isMouseOver = ref(<span class="hljs-literal">false</span>);
<span class="hljs-keyword">const</span> targetRef = ref&lt;HTMLDivElement&gt;();
<span class="hljs-keyword">const</span> dropdownStyle = ref({});
<span class="hljs-keyword">const</span> dropdownRef = ref&lt;HTMLDivElement&gt;();

<span class="hljs-keyword">const</span> existModalElement = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"modal"</span>);

<span class="hljs-keyword">if</span> (!existModalElement) {
  <span class="hljs-comment">// add modal element in body to prevent overflow issue</span>
  <span class="hljs-keyword">const</span> modalElement = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"div"</span>);
  modalElement.id = <span class="hljs-string">"modal"</span>;
  <span class="hljs-built_in">document</span>.body.appendChild(modalElement);
}

<span class="hljs-keyword">const</span> onMouseOver = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">if</span> (isMouseOver.value) {
    <span class="hljs-keyword">return</span>;
  }
  isMouseOver.value = <span class="hljs-literal">true</span>;
  <span class="hljs-keyword">const</span> dimension = targetRef.value.getBoundingClientRect();
  dropdownStyle.value = {
    width: <span class="hljs-string">`<span class="hljs-subst">${dimension.width}</span>px`</span>,
    left: <span class="hljs-string">`<span class="hljs-subst">${dimension.x}</span>px`</span>,
    top: <span class="hljs-string">`<span class="hljs-subst">${<span class="hljs-built_in">window</span>.scrollY + dimension.y + dimension.height + <span class="hljs-number">5</span>}</span>px`</span>,
  };
};

<span class="hljs-keyword">const</span> onMouseLeave = <span class="hljs-function">() =&gt;</span> {
  isMouseOver.value = <span class="hljs-literal">false</span>;
};
&lt;/script&gt;

&lt;template&gt;
  &lt;div <span class="hljs-meta">@mouseover</span>=<span class="hljs-string">"onMouseOver"</span> <span class="hljs-meta">@mouseleave</span>=<span class="hljs-string">"onMouseLeave"</span> ref=<span class="hljs-string">"targetRef"</span>&gt;
    &lt;slot name=<span class="hljs-string">"default"</span> /&gt;
  &lt;/div&gt;
  &lt;Teleport to=<span class="hljs-string">"#modal"</span>&gt;
    &lt;div
      ref=<span class="hljs-string">"dropdownRef"</span>
      :style=<span class="hljs-string">"dropdownStyle"</span>
      style=<span class="hljs-string">"position: absolute"</span>
      v-show=<span class="hljs-string">"isMouseOver"</span>
    &gt;
      &lt;Card&gt;
        &lt;slot name=<span class="hljs-string">"overlay"</span> /&gt;
      &lt;/Card&gt;
    &lt;/div&gt;
  &lt;/Teleport&gt;
&lt;/template&gt;
</code></pre>
<p>Finally, I will combine the components together like below</p>
<p>For the <strong>User Setting</strong> page, I will use the user card component which consists of card, avatar, name component and user detail components.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728285233747/fbd655bb-97e6-4628-94ec-9cba7523e95d.png" alt="user card component and user detail component" /></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// UserWithDescription.vue</span>
&lt;script setup lang=<span class="hljs-string">"ts"</span>&gt;
<span class="hljs-keyword">import</span> AppCard <span class="hljs-keyword">from</span> <span class="hljs-string">"./Card.vue"</span>;
<span class="hljs-keyword">import</span> DescriptionItem <span class="hljs-keyword">from</span> <span class="hljs-string">"./DescriptionItem.vue"</span>;
<span class="hljs-keyword">import</span> Avatar <span class="hljs-keyword">from</span> <span class="hljs-string">"./Avatar.vue"</span>;
<span class="hljs-keyword">import</span> UserName <span class="hljs-keyword">from</span> <span class="hljs-string">"./UserName.vue"</span>;
<span class="hljs-keyword">import</span> UserDescription <span class="hljs-keyword">from</span> <span class="hljs-string">"./UserDescription.vue"</span>;
<span class="hljs-keyword">import</span> { defineProps } <span class="hljs-keyword">from</span> <span class="hljs-string">"vue"</span>;

<span class="hljs-keyword">interface</span> Props {
  firstName: <span class="hljs-built_in">string</span>;
  lastName: <span class="hljs-built_in">string</span>;
  image?: <span class="hljs-built_in">string</span>;
  birthDate?: <span class="hljs-built_in">string</span>;
  phone?: <span class="hljs-built_in">string</span>;
  email?: <span class="hljs-built_in">string</span>;
  address?: <span class="hljs-built_in">string</span>;
}

<span class="hljs-keyword">const</span> props = defineProps&lt;Props&gt;();
&lt;/script&gt;

&lt;template&gt;
  &lt;AppCard&gt;
    &lt;Avatar :image=<span class="hljs-string">"image"</span> /&gt;
    &lt;div&gt;
      &lt;div&gt;
        &lt;UserName :firstName=<span class="hljs-string">"firstName"</span> :lastName=<span class="hljs-string">"lastName"</span> /&gt;
      &lt;/div&gt;
      &lt;UserDescription v-bind=<span class="hljs-string">"props"</span> /&gt;
    &lt;/div&gt;
  &lt;/AppCard&gt;
&lt;/template&gt;
</code></pre>
<p>As for the <strong>Employee Directory</strong> page, I plan for 2 combined components</p>
<ul>
<li><p>The basic user card component which consists of card, avatar and name components.</p>
</li>
<li><p>The user tooltip component which consists of card, tooltip and user detail components.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728285235086/dc48e260-fbee-441f-a9d4-0537aa6083f2.gif" alt="user card component and tooltip component" /></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// UserCard.vue</span>
&lt;script setup lang=<span class="hljs-string">"ts"</span>&gt;
    <span class="hljs-keyword">import</span> AppCard <span class="hljs-keyword">from</span> <span class="hljs-string">"./Card.vue"</span>;
    <span class="hljs-keyword">import</span> DescriptionItem <span class="hljs-keyword">from</span> <span class="hljs-string">"./DescriptionItem.vue"</span>;
    <span class="hljs-keyword">import</span> Avatar <span class="hljs-keyword">from</span> <span class="hljs-string">"./Avatar.vue"</span>;
    <span class="hljs-keyword">import</span> UserName <span class="hljs-keyword">from</span> <span class="hljs-string">"./UserName.vue"</span>;
    <span class="hljs-keyword">import</span> { defineProps } <span class="hljs-keyword">from</span> <span class="hljs-string">"vue"</span>;

    <span class="hljs-keyword">interface</span> Props {
        firstName: <span class="hljs-built_in">string</span>;
        lastName: <span class="hljs-built_in">string</span>;
        image?: <span class="hljs-built_in">string</span>;
    }

    <span class="hljs-keyword">const</span> props = defineProps&lt;Props&gt;();
&lt;/script&gt;

&lt;template&gt;
    &lt;AppCard&gt;
        &lt;Avatar :image=<span class="hljs-string">"image"</span> /&gt;
        &lt;div&gt;
            &lt;div&gt;
                &lt;UserName
                    :firstName=<span class="hljs-string">"firstName"</span>
                    :lastName=<span class="hljs-string">"lastName"</span> /&gt;
            &lt;/div&gt;
        &lt;/div&gt;
    &lt;/AppCard&gt;
&lt;/template&gt;
</code></pre>
<pre><code class="lang-plaintext">// UserCardWithTooltip.vue
&lt;script setup lang="ts"&gt;
    import ToolTip from "./Tooltip.vue";
    import UserDescription from "./UserDescription.vue";
    import UserCard from "./UserCard.vue";
    import Card from "./Card.vue";
    import { defineProps } from "vue";

    interface Props {
        firstName: string;
        lastName: string;
        image?: string;
        birthDate?: string;
        phone?: string;
        email?: string;
    }

    const props = defineProps&lt;Props&gt;();
&lt;/script&gt;

&lt;template&gt;
    &lt;ToolTip&gt;
        &lt;UserCard v-bind="props" /&gt;
        &lt;template #overlay&gt;
            &lt;Card&gt;
                &lt;UserDescription v-bind="props" /&gt;
            &lt;/Card&gt;
        &lt;/template&gt;
    &lt;/ToolTip&gt;
&lt;/template&gt;
</code></pre>
<p>For more details on the refactored codes of this case study, please check out the <a target="_blank" href="https://codesandbox.io/s/reusable-components-in-vue-wwsd5y?file=/src/components/solution/UserCardWithTooltip.vue">solution</a>.</p>
<p><em>Note: You may notice that the solution provide is based on Atomic Design concept. The concept can minimize the "reusability" challenge in the first place. If you are interested on how it can apply to Vue.js, please see my colleague's</em> <a target="_blank" href="https://dev.to/berryjam/introducing-atomic-design-in-vuejs-1l2h"><em>article</em></a><em>.</em></p>
<hr />
<h2 id="heading-do-unit-tests-help">Do Unit Tests Help?</h2>
<p>Some may think that writing unit tests for reusable components will ease this problem. It's true comprehensive test coverage helps ensure that modifications and enhancements to components do not accidentally break functionality.</p>
<p>However, unit tests do not make a component more reusable. It just makes it more robust. In fact, refactoring into smaller components breaks tasks into specific pieces and makes writing unit tests more manageable.</p>
<hr />
<h2 id="heading-conclusion">Conclusion</h2>
<p>Creating actual reusable components in Vue.js can be challenging due to issues related to modifying existing components, maintaining consistency, and managing dependencies and state. However, the benefits of reusable components make it worth overcoming these problems. Reusable components enhance code organization, improve development efficiency, and facilitate the creation of consistent user interfaces. As we face new requirements or tasks, we will improve so that we can better ourselves at designing reusable components.</p>
<hr />
<h2 id="heading-check-out-vue-pdf-viewer-for-your-next-project"><strong>Check Out Vue PDF Viewer for Your Next Project</strong></h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727947131835/59fe35c4-93e4-4cef-9e79-88fd84d5fc7f.png" alt="Vue PDF Viewer" /></p>
<p>If you’re working with Vue.js and need a PDF viewer that’s easy to integrate and highly customizable, you should check out <a target="_blank" href="https://www.vue-pdf-viewer.dev/?utm_source=blog&amp;utm_content=3-major-problems-of-reusable-components-in-vuejs"><strong>Vue PDF Viewer</strong></a>. It allows you to display PDFs directly within your Vue or Nuxt apps, with over 20 features including theme customization, localization, and responsive design.</p>
<p>I’d really appreciate it if you could give <a target="_blank" href="https://www.vue-pdf-viewer.dev/?utm_source=blog&amp;utm_content=3-major-problems-of-reusable-components-in-vuejs">Vue PDF Viewer</a> a try and let me know what you think! Your support will help me keep creating more useful tools and content 🙏🔥</p>
<p><img src="https://media.giphy.com/media/9uwnYUDw342pq/giphy.gif" alt class="image--center mx-auto" /></p>
]]></content:encoded></item><item><title><![CDATA[⚡️6 Most Popular Vue.js UI Libraries (Vue 3) in 2023 🔥]]></title><description><![CDATA[Edit: Previously I wrote about the "6 Most Popular Vue.js UI Libraries (Vue 3) in 2023". As we are now in 2024, I have revisited the different libraries and updated them for the current year 🎉
Vue.js, a JavaScript framework, has been gaining a lot o...]]></description><link>https://blog.vue-pdf-viewer.dev/6-most-popular-vuejs-ui-libraries-vue-3-in-2023</link><guid isPermaLink="true">https://blog.vue-pdf-viewer.dev/6-most-popular-vuejs-ui-libraries-vue-3-in-2023</guid><category><![CDATA[Vue.js]]></category><category><![CDATA[Nuxt.js]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[Frontend Development]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[TypeScript]]></category><category><![CDATA[Vuetify]]></category><category><![CDATA[Quasar Framework]]></category><dc:creator><![CDATA[Anson Chieng]]></dc:creator><pubDate>Wed, 13 Sep 2023 16:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1732703319651/1d6bd105-a42e-499e-bdf6-35c4d2bcfb80.avif" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>Edit: Previously I wrote about the "</em><a target="_blank" href="https://blog.vue-pdf-viewer.dev/6-most-popular-vuejs-ui-libraries-vue-3-in-2023"><em>6 Most Popular Vue.js UI Libraries (Vue 3) in 2023</em></a><em>". As we are now in 2024, I have revisited the different libraries and updated them for the current year 🎉</em></p>
<p>Vue.js, a JavaScript framework, has been gaining a lot of attention in recent years due to its simplicity, flexibility, and performance. Also, User Interface (UI) component libraries have become an essential aspect of web development, providing a fast and convenient way to build beautiful and responsive user interfaces.</p>
<p>Vue 3 has become the default choice to build modern applications since Vue 2 reaching its end of life on December 31, 2023. The need for UI component libraries designed specifically for Vue 3 has risen. In this article, we will take a look at the six most popular Vue.js UI component libraries for 2024, categorized based on their popularity within English and Chinese-speaking communities.</p>
<p>I decided to categorize this way because of massive popularity of Vue.js in China according to <a target="_blank" href="https://www.freecodecamp.org/news/between-the-wires-an-interview-with-vue-js-creator-evan-you-e383cbf57cc4/">an interview</a> with Evan You, the creator of Vue.js, who was born in China and grew up in a city near Shanghai.</p>
<p>Moreover, Vue has well written documents in Chinese. As teams from big companies in China such as Alibaba, Tencent and Baidu started using Vue.js, all these factors may have contributed to its popularity in the country.</p>
<hr />
<h2 id="heading-vue-pdf-viewer-flexible-and-powerful-vuejs-pdf-component">Vue-PDF-Viewer: Flexible and Powerful Vue.js PDF Component</h2>
<p>Just a quick background about what I’m working on. <a target="_blank" href="https://www.vue-pdf-viewer.dev/?utm_source=blog&amp;utm_content=top-6-vuejs-ui-libraries-vue-3-trending-in-2024">Vue-PDF-Viewer</a> renders the PDF viewer on your Vue or Nuxt websites so that your users can interact with your PDF document without leaving your sites. The component has over 20 features including theme customization, built-in localization, web responsive and more.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727947131835/59fe35c4-93e4-4cef-9e79-88fd84d5fc7f.png" alt="Vue PDF Viewer" /></p>
<p>I would be grateful if you could check <a target="_blank" href="https://www.vue-pdf-viewer.dev/?utm_source=blog&amp;utm_content=top-6-vuejs-ui-libraries-vue-3-trending-in-2024">Vue-PDF-Viewer</a> out. It will encourage me to make even more contents ❤️‍🔥</p>
<hr />
<h2 id="heading-english-focused-community">English focused community</h2>
<h3 id="heading-1-vuetify">1. Vuetify</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727947133471/c531ad19-e5e9-4993-8164-5f69ae5f4f9f.png" alt="Vuetify" /></p>
<p>Vuetify is a popular Vue.js UI component library based on Material Design specifications. It provides over 100 customizable components for creating beautiful and responsive user interfaces. With its modular design, developers can selectively import components, which keeps the bundle size small and improve performance.</p>
<p>Additionally, Vuetify integrates seamlessly with Nuxt 3 and features powerful theming capabilities where developers can customize their application style and match it with their brand.</p>
<p>As of February 2024, Vuetify has over 38,800 stars (from 37,900 stars in 2023) on GitHub and an average weekly downloads count of close to 500,000. (The <a target="_blank" href="https://npmtrends.com/vuetify">trend line</a> seems to be growing steadily over the years)</p>
<p>Learn more on <a target="_blank" href="https://vuetifyjs.com">https://vuetifyjs.com</a></p>
<p><em>Remark: There are still a couple of Vuetify 2 components including calendar, overflow-btn, speed-dial, time-picker and treeview that are not yet available in Vuetify 3. According to official Vuetify guide, they will be released by Vuetify Labs when development is completed.</em></p>
<h3 id="heading-2-quasar">2. Quasar</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727947134962/174409a3-585d-4328-b0a5-4b4fd665ccde.png" alt="Quasar" /></p>
<p>Quasar's UI Components feature 70 high performance customizable Material Design components and icons of various styles (bootstrap, material, fontawesome and many more). The documentation is detailed and well thought-out. The library also has pre-built features including animations and functions to handle dates and times.</p>
<p>What makes Quasar, founded since 2015, different and standout from other UI component libraries is that Quasar is not only a UI component library but a dynamic Vue framework. You can develop Vue.js desktop, web and mobile applications with a single codebase. As the saying goes, write once and use everywhere.</p>
<p>As of February 2024, Quasar has over 25,000 stars (from 24,200 stars in 2023) on GitHub and an average weekly downloads count of over 100,000.</p>
<p>Learn more on <a target="_blank" href="https://quasar.dev/">https://quasar.dev/</a></p>
<h3 id="heading-3-primevue">3. PrimeVue</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727947136401/94d98a40-22cf-44ed-b0ea-2b07c3186e76.png" alt="PrimeVue" /></p>
<p>PrimeVue is a sleek Vue.js component library that offers over 90 components and 200+ icons making it one of the most comprehensive libraries in the Vue.js community. It's a lightweight library with exclusive Tailwind CSS integration, enabling developers to build complex enterprise-level applications with ease.</p>
<p>PrimeVue is powered by PrimeTek, which serves millions of developers of Fortune 500 companies such as Intel, Nvidia and American Express, lending it massive credibility in the enterprise space.</p>
<p>PrimeVue also features an intuitive API, allowing developers to quickly customize the components to achieve their desired designs.</p>
<p>As of February 2024, PrimeVue has over 6,800 stars (from 4,300 stars in 2023) on GitHub and an average weekly downloads count of over 170,000 (<a target="_blank" href="https://npmtrends.com/primevue">Huge increase</a> from around 100,000 downloads in September 2023).</p>
<p>Learn more on <a target="_blank" href="https://primevue.org/">https://primevue.org/</a></p>
<hr />
<h2 id="heading-chinese-focused-community">Chinese focused community</h2>
<h3 id="heading-1-element-plus">1. Element Plus</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727947137699/99a2ceb2-b8c8-435a-b7a3-c16032e0a04a.png" alt="Element Plus" /></p>
<p>Element Plus is a community developed project born from Element UI which supports only Vue 2.X. Due to its predecessor's popularity, it has naturally gained a lot of attention by developers, especially those in China.</p>
<p>A TypeScript-based library with a complete type definition, Element Plus is not based on Material Design and has its own distinct UI style which can modified quite easily. Element Plus simplifies component utilization, making the code more maintainable and readable with Vue 3's Composition API.</p>
<p>As of February 2024, Element Plus has over 22,600 stars (from 21,300 stars in 2023) on GitHub and an average weekly downloads count of over 200,000.</p>
<p>Learn more on <a target="_blank" href="https://element-plus.org/en-US/">https://element-plus.org/en-US/</a></p>
<h3 id="heading-2-ant-design-vue">2. Ant Design Vue</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727947139698/1540192a-f9b1-4810-aed3-275128f610b6.png" alt="Ant Design Vue" /></p>
<p>Ant Design Vue (Antdv) is a popular TypeScript-based UI component library based off Ant Design, a library that was developed for React and was originally created by a team from Alibaba. But it has gained traction in the Vue.js community for its ease of use and its rich feature set. It offers a comprehensive range of components like tree structures, forms, and data visualization components.</p>
<p>Similar to Element Plus, Antdv has its own unique UI style. Although it may initially seem daunting to explore its huge sets of UI components and features, once you get the hang of it, Antdv can be a very powerful UI component library for projects of all sizes.</p>
<p>As of February 2024, Ant Design Vue has over 19,300 stars (from 18,600 stars in 2023) on GitHub and an average weekly downloads count of over 80,000.</p>
<p>Learn more on <a target="_blank" href="https://antdv.com/">https://antdv.com/</a></p>
<h3 id="heading-3-naive-ui">3. Naive UI</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727947140937/3979e157-41ce-48fb-8a29-7dd3e97a06d1.png" alt="Naive UI" /></p>
<p>Naive UI is a TypeScript-based UI component library developed by TuSimple, a Chinese autonomous truck company based in California. It has been mentioned by Evan You, the creator of Vue.js, in his Weibo blog back in 2021.</p>
<p>Naive UI consists of over 90 components that can be imported to use in your project. Most impressively, all 90+ components can be <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Glossary/Tree_shaking">treeshaken</a>. This means that the component can be imported individually into your application without waste. Documentation of Naive UI is also well documented and easy to follow.</p>
<p>As of February 2024, Naive UI has over 14,800 stars on GitHub and an average weekly downloads count of over 30,000.</p>
<p>Learn more on <a target="_blank" href="https://github.com/tusen-ai/naive-ui">https://github.com/tusen-ai/naive-ui</a></p>
<h3 id="heading-special-mention-nut-ui">Special Mention: Nut UI</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727947142628/362a147b-6816-4f08-b91f-81c667e7a6e7.png" alt="Nut UI" /></p>
<p>Nut UI is a mobile UI component library that is developed by the Chinese e-commerce giant, JD.com (also known as Jingdong). It provides a JD-style mobile UI component library that is used by JD in production.</p>
<p>Nut UI features high quality UI components that are well tested (unit test coverage more than 80%). It has clear documentation and supports TypeScript. Furthermore, it provides Sketch design resources for designers to easily create design screens.</p>
<p>As of February 2024, Nut UI has over 5,700 stars on GitHub and an average weekly downloads count of over 3,000.</p>
<p>Learn more on <a target="_blank" href="https://github.com/jdf2e/nutui/blob/v4/README_EN.md">https://github.com/jdf2e/nutui/blob/v4/README_EN.md</a></p>
<hr />
<h2 id="heading-conclusion">Conclusion</h2>
<p>In conclusion, Vue.js has gained popularity due to its flexibility, simplicity, and performance. The availability of different UI component libraries has made it easier for developers to build complex and elegant applications at speed with ease. Whether you're building large complex applications or small, highly performant ones, there is always the right Vue.js UI component library suitable for your needs.</p>
<hr />
<h2 id="heading-vue-pdf-viewer-flexible-and-powerful-vuejs-pdf-component-1">Vue-PDF-Viewer: Flexible and Powerful Vue.js PDF Component</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727947144455/0bed84c6-91e3-460a-b88d-9c924d673472.png" alt="Vue PDF Viewer" /></p>
<p>If you feel like this article helped you, please check out <a target="_blank" href="https://www.vue-pdf-viewer.dev/?utm_source=blog&amp;utm_content=top-6-vuejs-ui-libraries-vue-3-trending-in-2024">Vue-PDF-Viewer</a>. You can customize the PDF viewer component to your theme, add locales, configure panel and more. Each function has TS and JS codes, unit tests and interactive demos. With our starter kits, you can start rendering the <a target="_blank" href="https://www.vue-pdf-viewer.dev/?utm_source=blog&amp;utm_content=top-6-vuejs-ui-libraries-vue-3-trending-in-2024">Vue-PDF-Viewer</a> in minutes.</p>
<p>It would encourage me to continue creating even more contents. Thank you in advance! 🙏</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://media.giphy.com/media/QLtO7Hs5FXtJe/giphy.gif">https://media.giphy.com/media/QLtO7Hs5FXtJe/giphy.gif</a></div>
]]></content:encoded></item><item><title><![CDATA[⚛️ Introducing Atomic Design in Vue.js 🔥]]></title><description><![CDATA[In my experience of building and delivering systems for various clients, depending on their requirements or preferences, it’s inevitable that I may use UI frameworks and libraries like Ant Design and Tailwind. Often, I have to build on top of each co...]]></description><link>https://blog.vue-pdf-viewer.dev/introducing-atomic-design-in-vuejs</link><guid isPermaLink="true">https://blog.vue-pdf-viewer.dev/introducing-atomic-design-in-vuejs</guid><category><![CDATA[Vue.js]]></category><category><![CDATA[Nuxt]]></category><category><![CDATA[TypeScript]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[Frontend Development]]></category><dc:creator><![CDATA[Kittisak Ma]]></dc:creator><pubDate>Tue, 22 Aug 2023 16:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1728399650998/e0c0f7d2-7942-4abc-8ddb-e4b9b00bac9f.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In my experience of building and delivering systems for various clients, depending on their requirements or preferences, it’s inevitable that I may use UI frameworks and libraries like <a target="_blank" href="https://antdv.com/">Ant Design</a> and <a target="_blank" href="https://tailwindcss.com/">Tailwind</a>. Often, I have to build on top of each components. If you are working alone, it’s not such a big problem. But when working as a team, things get complicated quickly.</p>
<p>So, I started looking at different methodologies which can provide development flexibility and system maintainability for the projects I’m leading. I choose Atomic Design methodology and want to share why it works for me.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728374895588/79182537-fef1-43a2-b151-21f8a9ef6728.png" alt="Atomic Design Concept" /></p>
<p><a target="_blank" href="https://bradfrost.com/blog/post/atomic-web-design/">Atomic Design</a> is a methodology for creating design systems that breaks down user interfaces into small, reusable components, namely:</p>
<ol>
<li><p>Atoms</p>
</li>
<li><p>Molecules</p>
</li>
<li><p>Organisms</p>
</li>
<li><p>Templates</p>
</li>
<li><p>Pages</p>
</li>
</ol>
<p>By following a modular approach to design, atomic design helps teams to create consistent, scalable, and maintainable UIs.</p>
<p>In this post, for simplicity, we'll explore how to implement Atomic Design in <a target="_blank" href="https://vuejs.org/">Vue.js</a> with only HTML. I'll start with the basics of Atomic Design and then demonstrate how to apply its principles in Vue.js.</p>
<p>At the end of the article, you will get a page that consists of a header, a form and a footer. You can use the example here to apply to any UI framework.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728374897266/e0a5e63b-cc8d-455d-97f5-d9af449f8e99.png" alt="Image atomic design with vue components" /></p>
<p><em>You may notice that each component has borders around it. This is intentional so you can identify whether it's an atom, a molecule, or an organism.</em></p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://media.giphy.com/media/jYLMZUnqZqLb2p113v/giphy.gif?cid=ecf05e47bfs80xgcgycafoyr54d2sc79gpeves573ef4v4dl&amp;ep=v1_gifs_search&amp;rid=giphy.gif&amp;ct=g">https://media.giphy.com/media/jYLMZUnqZqLb2p113v/giphy.gif?cid=ecf05e47bfs80xgcgycafoyr54d2sc79gpeves573ef4v4dl&amp;ep=v1_gifs_search&amp;rid=giphy.gif&amp;ct=g</a></div>
<p> </p>
<hr />
<h2 id="heading-vue-pdf-viewer-a-versatile-and-powerful-pdf-solution-for-vuejs">Vue-PDF-Viewer: A Versatile and Powerful PDF Solution for Vue.js</h2>
<p>Here’s a little background on what I’ve been working on—<a target="_blank" href="https://www.vue-pdf-viewer.dev/?utm_source=blog&amp;utm_campaign=introducing-atomic-design-in-vuejs">Vue PDF Viewer</a>. This library makes it easy to render PDF documents right within your Vue or Nuxt applications, allowing users to interact with PDFs directly on your site. With features like theme customization, built-in localization, and responsive design, it’s crafted to offer a flexible and seamless user experience tailored to your project’s needs.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728272164119/9df36d8a-70a3-4856-b47c-417a22d37665.png" alt="Vue PDF Viewer" /></p>
<p>If you find this helpful, I’d love for you to check out <a target="_blank" href="https://www.vue-pdf-viewer.dev/?utm_source=blog&amp;utm_campaign=introducing-atomic-design-in-vuejs">Vue PDF Viewer</a>. Your support inspires me to keep creating and improving tools for the developer community!</p>
<hr />
<h2 id="heading-anatomy-of-atomic-design">Anatomy of Atomic Design</h2>
<p>Atomic Design consists of five levels that represent the building blocks of UIs. For this example, I have created an inverted tree structure to visualizing how each anatomy is connected.</p>
<pre><code class="lang-typescript">- Page
 - Full Layout Template
  - Header Organism
    - Logo Atom
    - Search Form Molecule
      - TextBox Atom
      - Button Atom
  - Content Organsim
    - Form Molecule
      - <span class="hljs-number">2</span>x TextBox Atoms
      - Button Atom
  - Footer Organism
    - Copyright Atom
    - Subscribe Form Molecule
      - TextBox Atom
      - Button Atom
</code></pre>
<h3 id="heading-1-atoms"><strong>1. Atoms</strong></h3>
<p>Atoms are the smallest units of UI that cannot be broken down further without losing their meaning. Examples of atoms include icons, buttons, labels, inputs, and typography.</p>
<p>In Vue.js, atoms can be created as reusable components that accept props to customize their appearance and behavior. For this instance, we have a few atoms to prepare for:</p>
<ul>
<li><p>Textbox</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728374899103/d45fb263-3516-4081-9e10-8551a4ebd6b7.png" alt="Image textBoxAtom" /></p>
</li>
</ul>
<pre><code class="lang-typescript">&lt;template&gt;
&lt;div <span class="hljs-keyword">class</span>=<span class="hljs-string">"component-wrapper"</span> data-name=<span class="hljs-string">"textBoxAtom"</span>&gt;
  &lt;label&gt;{{ label }}: &lt;input <span class="hljs-keyword">type</span>=<span class="hljs-string">"text"</span> :placeholder=<span class="hljs-string">"placeHolder"</span> /&gt;&lt;/label&gt;
&lt;/div&gt;
&lt;/template&gt; 

&lt;script&gt;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> { 
  name: <span class="hljs-string">'TextBoxAtom'</span>, 
  props: { 
    label: {
      <span class="hljs-keyword">type</span>: <span class="hljs-built_in">String</span>,
      <span class="hljs-keyword">default</span>: <span class="hljs-string">'labelName'</span>
    }, 
    placeHolder: <span class="hljs-built_in">String</span>, 
  }, 
}; 
&lt;/script&gt;
&lt;style scoped&gt;
  input{
      padding: <span class="hljs-number">0.75</span>em <span class="hljs-number">2</span>em;
  }
&lt;/style&gt;
</code></pre>
<ul>
<li><p>Button</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728374900649/7e272f91-3513-46bf-8c72-9a4a556be5f7.png" alt="Image buttonAtom" /></p>
</li>
</ul>
<pre><code class="lang-typescript">&lt;template&gt;
 &lt;div <span class="hljs-keyword">class</span>=<span class="hljs-string">"component-wrapper"</span> data-name=<span class="hljs-string">"buttonAtom"</span>&gt;
  &lt;button :disabled=<span class="hljs-string">"disabled"</span>&gt; 
    &lt;slot&gt;Button&lt;/slot&gt;
  &lt;/button&gt; 
 &lt;/div&gt;
&lt;/template&gt; 

&lt;script&gt;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> { 
  name: <span class="hljs-string">'ButtonAtom'</span>, 
  props: { 
    <span class="hljs-keyword">type</span>: <span class="hljs-built_in">String</span>, 
    size: <span class="hljs-built_in">String</span>, 
    disabled: <span class="hljs-built_in">Boolean</span>,
  },  
}; 
&lt;/script&gt;
&lt;style scoped&gt;
button {
  color: #<span class="hljs-number">4</span>fc08d;
}
button {
  background: none;
  border: solid <span class="hljs-number">1</span>px;
  border-radius: <span class="hljs-number">2</span>em;
  font: inherit;
  padding: <span class="hljs-number">0.5</span>em <span class="hljs-number">2</span>em;
}
&lt;/style&gt;
</code></pre>
<ul>
<li><p>Logo</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728374901547/b9e3fe0b-d6d8-4c4d-89bf-956c9f6c47ea.png" alt="Image logoAtom" /></p>
</li>
</ul>
<pre><code class="lang-typescript">&lt;template&gt;
  &lt;div <span class="hljs-keyword">class</span>=<span class="hljs-string">"component-wrapper"</span> data-name=<span class="hljs-string">"logoAtom"</span>&gt;
    &lt;img :src=<span class="hljs-string">"computedImageUrl"</span> alt=<span class="hljs-string">"logo"</span>/&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  props: {
    width: {
      <span class="hljs-keyword">type</span>: <span class="hljs-built_in">Number</span>,
      <span class="hljs-keyword">default</span>: <span class="hljs-number">50</span>
    },
    height: {
      <span class="hljs-keyword">type</span>: <span class="hljs-built_in">Number</span>,
      <span class="hljs-keyword">default</span>: <span class="hljs-number">50</span>
    }
  },
  computed: {
    computedImageUrl() {
      <span class="hljs-keyword">return</span> <span class="hljs-string">`https://picsum.photos/<span class="hljs-subst">${<span class="hljs-built_in">this</span>.width}</span>/<span class="hljs-subst">${<span class="hljs-built_in">this</span>.height}</span>`</span>
    }
  }
};
&lt;/script&gt;
</code></pre>
<p>For a closer look, you can check out the codes in the <a target="_blank" href="https://codepen.io/collection/xKagKz">Atoms collection</a>.</p>
<h3 id="heading-2-molecules"><strong>2. Molecules</strong></h3>
<p>Molecules are combinations of two or more atoms that work together to perform a specific function. In Vue.js, molecules can be created by composing atoms as child components within a parent component. Examples of molecules include forms, search bars, navigation menus, and cards.</p>
<p>Referring to the example above, we will need to combine the atoms to create the following molecules:</p>
<ul>
<li><p>Subscribe Form Molecule</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728374902571/6246eed6-7c38-41c9-8e0f-93a2ccd6468f.png" alt="Image subscribeFormMolecule" /></p>
</li>
</ul>
<pre><code class="lang-typescript">&lt;template&gt;
  &lt;form <span class="hljs-keyword">class</span>=<span class="hljs-string">"component-wrapper"</span> data-name=<span class="hljs-string">"subscribeFormMolecules"</span>&gt;
    &lt;TextboxAtom label=<span class="hljs-string">"Email"</span> /&gt;
    &amp;nbsp;
    &lt;ButtonAtom&gt;Subscribe&lt;/ButtonAtom&gt;
  &lt;/form&gt;
&lt;/template&gt;

&lt;script&gt;
<span class="hljs-keyword">import</span> TextboxAtom <span class="hljs-keyword">from</span> <span class="hljs-string">"https://codepen.io/9haroon/pen/LYXgdKg.js"</span>;
<span class="hljs-keyword">import</span> ButtonAtom <span class="hljs-keyword">from</span> <span class="hljs-string">"https://codepen.io/9haroon/pen/BaGqrJg.js"</span>;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  components: { ButtonAtom, TextboxAtom }
};
&lt;/script&gt;
&lt;style scoped&gt;
form {
  display: inline-flex;
}
&lt;/style&gt;
</code></pre>
<ul>
<li><p>Search Form Molecule</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728374903609/d11de4a3-62b7-4640-a48c-ff371230e258.png" alt="Image searchFormMolecule" /></p>
</li>
</ul>
<pre><code class="lang-typescript">&lt;template&gt;
  &lt;form <span class="hljs-keyword">class</span>=<span class="hljs-string">"component-wrapper"</span> data-name=<span class="hljs-string">"searchFormMolecules"</span>&gt;
    &lt;InputAtom label=<span class="hljs-string">"Search"</span> /&gt;
    &lt;ButtonAtom&gt;Search&lt;/ButtonAtom&gt;
  &lt;/form&gt;
&lt;/template&gt;

&lt;script&gt;
<span class="hljs-keyword">import</span> InputAtom <span class="hljs-keyword">from</span> <span class="hljs-string">"https://codepen.io/9haroon/pen/LYXgdKg.js"</span>;
<span class="hljs-keyword">import</span> ButtonAtom <span class="hljs-keyword">from</span> <span class="hljs-string">"https://codepen.io/9haroon/pen/BaGqrJg.js"</span>;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  components: { ButtonAtom, InputAtom }
};
&lt;/script&gt;
&lt;style scoped&gt;
form {
  display: inline-flex;
}
&lt;/style&gt;
</code></pre>
<ul>
<li><p>Form Molecule</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728374905077/b9c862e0-f25d-44e1-9a92-ce644e9e86e1.png" alt="Image formMolecule" /></p>
</li>
</ul>
<pre><code class="lang-typescript">&lt;template&gt;
  &lt;div <span class="hljs-keyword">class</span>=<span class="hljs-string">"form-molecule component-wrapper"</span> data-name=<span class="hljs-string">"formMolecules"</span>&gt;
    &lt;div&gt;&lt;InputAtom :label=<span class="hljs-string">"nameLabel"</span> :placeholder=<span class="hljs-string">"namePlaceholder"</span> /&gt;&lt;/div&gt;
    &lt;div&gt;&lt;InputAtom :label=<span class="hljs-string">"emailLabel"</span> :placeholder=<span class="hljs-string">"emailPlaceholder"</span> /&gt;&lt;/div&gt;
    &lt;p&gt;
      &lt;ButtonAtom :disabled=<span class="hljs-string">"isSubmitDisabled"</span>&gt;
        {{ submitLabel || <span class="hljs-string">"Button"</span> }}
      &lt;/ButtonAtom&gt;
    &lt;/p&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
<span class="hljs-keyword">import</span> InputAtom <span class="hljs-keyword">from</span> <span class="hljs-string">"https://codepen.io/9haroon/pen/LYXgdKg.js"</span>;
<span class="hljs-keyword">import</span> ButtonAtom <span class="hljs-keyword">from</span> <span class="hljs-string">"https://codepen.io/9haroon/pen/BaGqrJg.js"</span>;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  name: <span class="hljs-string">"FormMolecule"</span>,
  components: {
    InputAtom,
    ButtonAtom
  },
  props: {
    nameLabel: <span class="hljs-built_in">String</span>,
    namePlaceholder: <span class="hljs-built_in">String</span>,
    emailLabel: <span class="hljs-built_in">String</span>,
    emailPlaceholder: <span class="hljs-built_in">String</span>,
    submitLabel: <span class="hljs-built_in">String</span>,
    isSubmitDisabled: <span class="hljs-built_in">Boolean</span>
  }
};
&lt;/script&gt;
</code></pre>
<p>You can find the codes in the <a target="_blank" href="https://codepen.io/collection/qOkROP">Molecules collection</a>.</p>
<h3 id="heading-3-organisms"><strong>3. Organisms</strong></h3>
<p>Organisms are combinations of molecules that form distinct sections of a UI, such as headers, footers, sidebars, and content blocks. In Vue.js, organisms can be created by composing molecules as child components within a layout component.</p>
<p>For this exercise, three organisms are needed.</p>
<ul>
<li><p>Header Organism</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728374906180/57dd90a7-d926-4a2e-9a98-73f27eb71338.png" alt="Image headerOrganism" /></p>
</li>
</ul>
<pre><code class="lang-typescript">&lt;template&gt;
  &lt;header <span class="hljs-keyword">class</span>=<span class="hljs-string">"component-wrapper"</span> data-name=<span class="hljs-string">"headerOrganism"</span>&gt;
    &lt;LogoAtom width=<span class="hljs-string">"60"</span> /&gt;
    &lt;SearchFormMoecules /&gt;
  &lt;/header&gt;
&lt;/template&gt;

&lt;script&gt;
<span class="hljs-keyword">import</span> SearchFormMoecules <span class="hljs-keyword">from</span> <span class="hljs-string">"https://codepen.io/9haroon/pen/zYMmjqa.js"</span>;
<span class="hljs-keyword">import</span> LogoAtom <span class="hljs-keyword">from</span> <span class="hljs-string">"https://codepen.io/9haroon/pen/xxQMbeJ.js"</span>;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  components: { SearchFormMoecules, LogoAtom }
};
&lt;/script&gt;
&lt;style scoped&gt;
header {
  min-height: <span class="hljs-number">50</span>px;
  display: flex;
  justify-content: space-between;
  align-items: center;
}
&lt;/style&gt;
</code></pre>
<ul>
<li><p>Content Organism</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728374907223/3c6f918c-170c-4f20-8673-6bb5fde284d4.png" alt="Image contentOrganism" /></p>
</li>
</ul>
<pre><code class="lang-typescript">&lt;template&gt;
  &lt;div <span class="hljs-keyword">class</span>=<span class="hljs-string">"page-organism"</span>&gt;
    &lt;div <span class="hljs-keyword">class</span>=<span class="hljs-string">"content-wrapper-title"</span>&gt;
      &lt;h1&gt;&lt;slot name=<span class="hljs-string">"title"</span>&gt;Here might be a page title&lt;<span class="hljs-regexp">/slot&gt;&lt;/</span>h1&gt;
      &lt;p&gt;&lt;slot name=<span class="hljs-string">"description"</span>&gt;Here might be a page description&lt;<span class="hljs-regexp">/slot&gt;&lt;/</span>p&gt;
    &lt;/div&gt;
    &lt;slot&gt;...&lt;/slot&gt;
    &lt;!--   This might includes some molecules or atoms   --&gt;
  &lt;/div&gt;
&lt;/template&gt;
&lt;script&gt;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  name: <span class="hljs-string">"ContentOrganism"</span>,
  components: {}
};
&lt;/script&gt;
&lt;style scoped&gt;
.page-organism {
  padding-top: <span class="hljs-number">50</span>px;
  padding-bottom: <span class="hljs-number">80</span>px;
  box-shadow: inset <span class="hljs-number">0</span>px <span class="hljs-number">10</span>px <span class="hljs-number">15</span>px <span class="hljs-number">-3</span>px rgba(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.1</span>);
}
.content-wrapper-title {
  text-align: center;
}
&lt;/style&gt;
</code></pre>
<ul>
<li><p>Footer Organism</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728374908758/a72124be-79d1-40a2-9d3d-bb1de6d38335.png" alt="Image footerOrganism" /></p>
</li>
</ul>
<pre><code class="lang-typescript">&lt;template&gt;
  &lt;footer <span class="hljs-keyword">class</span>=<span class="hljs-string">"component-wrapper"</span> data-name=<span class="hljs-string">"footerOrganism"</span>&gt;
    &lt;CopyrightAtom /&gt;
    &lt;SubscribeFormMoecules /&gt;
  &lt;/footer&gt;
&lt;/template&gt;

&lt;script&gt;
<span class="hljs-keyword">import</span> SubscribeFormMoecules <span class="hljs-keyword">from</span> <span class="hljs-string">"https://codepen.io/9haroon/pen/ExOrarL.js"</span>;
<span class="hljs-keyword">import</span> LogoAtom <span class="hljs-keyword">from</span> <span class="hljs-string">"https://codepen.io/9haroon/pen/xxQMbeJ.js"</span>;
<span class="hljs-keyword">import</span> CopyrightAtom <span class="hljs-keyword">from</span> <span class="hljs-string">"https://codepen.io/9haroon/pen/gOQqOBj.js"</span>;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  components: { SubscribeFormMoecules, LogoAtom, CopyrightAtom }
};
&lt;/script&gt;
&lt;style scoped&gt;
footer {
  display: flex;
  justify-content: space-between;
  align-items: center;
}
&lt;/style&gt;
</code></pre>
<p>Per usual, here's a <a target="_blank" href="https://codepen.io/collection/LPJxPO">collection of organisms' codes</a> that I've created.</p>
<h3 id="heading-4-templates"><strong>4. Templates</strong></h3>
<p>Templates are the structures that define the layout and composition of pages by specifying the placement and size of organisms within regions, such as headers, footers, and content areas.</p>
<p>In Vue.js, templates can be created as parent components that accept named slots for child components. Applying the 3 organisms to the <em>Templates</em> concept, here is how it could look like.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728374909865/e2fb27ad-7561-43a7-85eb-e575993fb35a.png" alt="Image fullLayoutTemplate" /></p>
<pre><code class="lang-typescript">&lt;template&gt;
  &lt;div <span class="hljs-keyword">class</span>=<span class="hljs-string">"full-layout-template"</span>&gt;
    &lt;HeaderOrganism /&gt;
    &lt;ContentOrganism <span class="hljs-keyword">class</span>=<span class="hljs-string">"content"</span>&gt;
      &lt;template #title&gt;
        &lt;slot name=<span class="hljs-string">"title"</span>&gt;<span class="hljs-keyword">default</span> title&lt;/slot&gt;
      &lt;/template&gt;
      &lt;template #description&gt;
        &lt;slot name=<span class="hljs-string">"description"</span>&gt;<span class="hljs-keyword">default</span> description&lt;/slot&gt;
      &lt;/template&gt;
      &lt;slot /&gt;
    &lt;/ContentOrganism&gt;
    &lt;FooterOrganism <span class="hljs-keyword">class</span>=<span class="hljs-string">"page-footer"</span> /&gt;
  &lt;/div&gt;
&lt;/template&gt;
&lt;script&gt;
<span class="hljs-keyword">import</span> HeaderOrganism <span class="hljs-keyword">from</span> <span class="hljs-string">"https://codepen.io/9haroon/pen/WNYaJGR.js"</span>;
<span class="hljs-keyword">import</span> ContentOrganism <span class="hljs-keyword">from</span> <span class="hljs-string">"https://codepen.io/9haroon/pen/vYQbOeO.js"</span>;
<span class="hljs-keyword">import</span> FooterOrganism <span class="hljs-keyword">from</span> <span class="hljs-string">"https://codepen.io/9haroon/pen/RwqvPRN.js"</span>;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  name: <span class="hljs-string">"FullLayoutTemplate"</span>,
  components: {
    HeaderOrganism,
    ContentOrganism,
    FooterOrganism
  }
};
&lt;/script&gt;
&lt;style scoped&gt;
.full-layout-template {
  display: flex;
  flex-direction: column;
  min-height: <span class="hljs-number">90</span>vh;
}
.content {
  flex: <span class="hljs-number">1</span> <span class="hljs-number">0</span> auto;
}
.page-footer {
  flex-shrink: <span class="hljs-number">0</span>;
}
&lt;/style&gt;
</code></pre>
<p>here is the <a target="_blank" href="https://codepen.io/9haroon/pen/GRwzpxx">CodePen's link</a> of the template</p>
<h3 id="heading-5-pages"><strong>5. Pages</strong></h3>
<p>Pages are the final presentation of UIs that combine templates with specific content to form complete views. In Atomic Design, pages are like instances of templates that represent unique experiences for users.</p>
<p>In Vue.js, pages can be created by copying a template and replacing its slots with actual content. Although, in this example, I only change the content of <em>Content Organism</em>, you could choose to change all or no content.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728374911337/f9afe10e-8122-49c5-931d-55f58936d7cd.png" alt="Image homePage" /></p>
<pre><code class="lang-typescript">&lt;template&gt;
  &lt;FullLayoutTemplate&gt;
    &lt;template #title&gt;{{ title }}&lt;/template&gt;
    &lt;template #description&gt;{{ description }}&lt;/template&gt;
    &lt;div <span class="hljs-keyword">class</span>=<span class="hljs-string">"fixed-width"</span>&gt;
      &lt;FormMolecule nameLabel=<span class="hljs-string">"Name"</span> emailLabel=<span class="hljs-string">"Email"</span> submitLabel=<span class="hljs-string">"Save"</span> /&gt;
    &lt;/div&gt;
  &lt;/FullLayoutTemplate&gt;
&lt;/template&gt;
&lt;script&gt;
<span class="hljs-keyword">import</span> FullLayoutTemplate <span class="hljs-keyword">from</span> <span class="hljs-string">"https://codepen.io/9haroon/pen/GRwzpxx.js"</span>;
<span class="hljs-keyword">import</span> FormMolecule <span class="hljs-keyword">from</span> <span class="hljs-string">"https://codepen.io/9haroon/pen/PoxyRMo.js"</span>;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  name: <span class="hljs-string">"HomePage"</span>,
  components: {
    FullLayoutTemplate,
    FormMolecule
  },
  data() {
    <span class="hljs-keyword">return</span> {
      title: <span class="hljs-string">"Welcome to my example"</span>,
      description: <span class="hljs-string">"This is an example of Atomic Design in Vue.js"</span>,
      copyright: <span class="hljs-string">"Copyright © 2023"</span>
    };
  }
};
&lt;/script&gt;
&lt;style scoped&gt;
* {
  font-family: Avenir, Helvetica, Arial, sans-serif;
}
.fixed-width {
  max-width: <span class="hljs-number">350</span>px;
  margin: <span class="hljs-number">0</span> auto;
}
&lt;/style&gt;
</code></pre>
<p>here is the <a target="_blank" href="https://codepen.io/9haroon/pen/qBQgOGj">CodePen's link</a> of the page</p>
<p><img src="https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExbXVmOHF4ZHczZG15Y281djFzb3U3ZXRqeWliZHg5Y2N5MWloaGVnNiZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/Y655D2pOIBCQU/giphy.gif" alt class="image--center mx-auto" /></p>
<hr />
<h2 id="heading-benefits-of-atomic-design-in-vuejs">Benefits of Atomic Design in Vue.js</h2>
<p>By using Atomic Design in Vue.js, you can achieve several benefits, such as:</p>
<ul>
<li><p><strong>Consistency</strong>: By creating reusable components, you ensure that your UIs look and behave consistently across all pages.</p>
</li>
<li><p><strong>Scalability</strong>: By breaking down UIs into small pieces, you can easily add, remove, or update components without affecting other parts of the system.</p>
</li>
<li><p><strong>Maintainability</strong>: By organizing components into folders and files, you can easily find, edit, or debug them in isolation from other parts of the system.</p>
</li>
<li><p><strong>Reusability</strong>: By creating standalone components, you can reuse them in other projects or share them with the community, thus saving time and effort.</p>
</li>
</ul>
<p>Atomic Design is a powerful methodology that can help you design better UIs in Vue.js. By following its principles, you can create reusable, modular, and scalable components that make your code more maintainable and your users more satisfied. So, go ahead, give it a try, and let me know how it worked for you!</p>
<p><img src="https://media.giphy.com/media/3og0IPMeREHpEV0f60/giphy.gif" alt class="image--center mx-auto" /></p>
<hr />
<h2 id="heading-vue-pdf-viewer-a-complete-pdf-solution-for-vuejs">Vue PDF Viewer: A Complete PDF Solution for Vue.js</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728272164119/9df36d8a-70a3-4856-b47c-417a22d37665.png" alt="Vue PDF Viewer" /></p>
<p>If you’re looking for a powerful, flexible solution for rendering PDFs directly in your Vue or Nuxt applications, <a target="_blank" href="https://www.vue-pdf-viewer.dev/?utm_source=blog&amp;utm_campaign=introducing-atomic-design-in-vuejs">Vue PDF Viewer</a> is the tool for you. Offering a wide array of features—like theme customization, localization support, and responsive layouts—it’s built to handle a range of project requirements while delivering a seamless, user-friendly experience.</p>
<p>If this sounds useful to you, feel free to explore <a target="_blank" href="https://www.vue-pdf-viewer.dev/?utm_source=blog&amp;utm_campaign=introducing-atomic-design-in-vuejs">Vue PDF Viewer</a> and see how it can enhance your next project. It would mean the world and encourage me to create more content.</p>
<p>Thank you in advance! 🙏</p>
<p><img src="https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExZm9xcTFxNWFoMW93czhjcWpleTF3bjM2b2VidnBpcTVoMjZibzlxcSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/dvxq3BtNLK6KEgTryW/giphy.gif" alt class="image--center mx-auto" /></p>
]]></content:encoded></item></channel></rss>