<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Muhammad Hamid Raza</title>
    <description>The latest articles on DEV Community by Muhammad Hamid Raza (@hamidrazadev).</description>
    <link>https://dev.to/hamidrazadev</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3131979%2F8333e423-4d9b-4851-ab42-f268ef4993c4.png</url>
      <title>DEV Community: Muhammad Hamid Raza</title>
      <link>https://dev.to/hamidrazadev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/hamidrazadev"/>
    <language>en</language>
    <item>
      <title>Why Most Developers Love Dark Mode (And It's Not Just a Vibe)</title>
      <dc:creator>Muhammad Hamid Raza</dc:creator>
      <pubDate>Sat, 09 May 2026 10:45:22 +0000</pubDate>
      <link>https://dev.to/hamidrazadev/why-most-developers-love-dark-mode-and-its-not-just-a-vibe-3no6</link>
      <guid>https://dev.to/hamidrazadev/why-most-developers-love-dark-mode-and-its-not-just-a-vibe-3no6</guid>
      <description>&lt;p&gt;You open your laptop at 11 PM to fix "just one bug." The screen blasts you with a wall of white light. Your eyes feel like they're being interrogated. Sound familiar? 😅&lt;/p&gt;

&lt;p&gt;Dark mode has quietly become the unofficial uniform of the developer world. Open any code editor, terminal, browser dev tool, or GitHub repo — chances are it's dressed in dark. But why exactly? Is it just aesthetic? Is it a productivity thing? Or are developers just wired to love the night?&lt;/p&gt;

&lt;p&gt;Let's dig into the real reasons why most developers swear by dark mode, and whether it actually deserves all the love it gets.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Is Dark Mode?
&lt;/h2&gt;

&lt;p&gt;Dark mode is a display setting that flips the default color scheme of an interface. Instead of dark text on a white background, you get light text on a dark (usually near-black or deep gray) background.&lt;/p&gt;

&lt;p&gt;It's available in almost every modern OS, browser, app, and code editor today — from VS Code and JetBrains IDEs to GitHub, Twitter, Discord, and even Google Docs.&lt;/p&gt;

&lt;p&gt;Think of it like switching from a fluorescent office room to a cozy desk lamp setup. Same work. Very different vibe — and for many, very different comfort.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Dark Mode Matters for Developers
&lt;/h2&gt;

&lt;p&gt;Developers don't just stare at screens occasionally. They stare at screens &lt;em&gt;all day&lt;/em&gt;. Sometimes all night too.&lt;/p&gt;

&lt;p&gt;When your job involves reading thousands of lines of code, debugging complex logic, and switching between dozens of tabs — how your screen looks isn't a minor detail. It directly affects how long you can work comfortably, how quickly your eyes tire, and even how focused you feel.&lt;/p&gt;

&lt;p&gt;That's exactly why dark mode isn't just a trend for developers. For many, it's a genuine quality-of-life upgrade.&lt;/p&gt;




&lt;h2&gt;
  
  
  Real Reasons Developers Love Dark Mode
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. 🔧 It Reduces Eye Strain During Long Sessions
&lt;/h3&gt;

&lt;p&gt;This is the big one. Staring at a bright white screen for 8+ hours is genuinely tiring. Dark mode reduces the overall amount of light your screen emits, which can reduce the strain on your eyes — especially in dim or nighttime environments.&lt;/p&gt;

&lt;p&gt;It's not a magic cure, but many developers notice real relief after switching. Fewer headaches. Less of that burning sensation by 6 PM.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. 💡 Code Just Looks Better on Dark Backgrounds
&lt;/h3&gt;

&lt;p&gt;Syntax highlighting — the colorful way editors display different parts of your code — pops brilliantly against dark backgrounds. Keywords in blue, strings in green, comments in gray — they stand out clearly and make code much easier to scan.&lt;/p&gt;

&lt;p&gt;On a white background, those same colors feel flatter and harder to distinguish at a glance. If you want your code to feel alive, dark mode is where syntax highlighting truly shines.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. 🌙 It Matches the Developer's Natural Habitat
&lt;/h3&gt;

&lt;p&gt;Developers often work late. Deadlines don't care about time zones. When everyone else is asleep and you're still pushing commits, a pitch-black terminal on a black background feels less aggressive on your environment — and on your mood.&lt;/p&gt;

&lt;p&gt;Dark mode also reduces how much light your screen throws into the room, which is genuinely considerate if you're sharing a space with someone sleeping nearby.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. ⚡ It Saves Battery on OLED and AMOLED Screens
&lt;/h3&gt;

&lt;p&gt;On OLED and AMOLED displays — which are common on modern laptops and phones — true black pixels are literally turned off. Dark mode means fewer lit pixels, which means less power consumption.&lt;/p&gt;

&lt;p&gt;For developers who code on their laptops without a charger, dark mode can genuinely squeeze extra time out of a battery. Practical and stylish.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. 👀 It Creates a Focused, Distraction-Free Atmosphere
&lt;/h3&gt;

&lt;p&gt;There's a psychological side too. A dark interface naturally draws your attention toward the content — the code, the text, the task at hand — rather than the white space around it.&lt;/p&gt;

&lt;p&gt;Many developers describe dark mode as creating a sort of "tunnel vision" that helps them stay focused. It's the coding equivalent of noise-canceling headphones.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. 🚀 It Looks Professional and Clean
&lt;/h3&gt;

&lt;p&gt;Let's be honest — dark mode just looks good. There's a reason tech companies, dev tools, and portfolio sites often default to dark themes. It signals sophistication, technical seriousness, and modern design taste.&lt;/p&gt;

&lt;p&gt;If you're screensharing your code in a presentation or live streaming your workflow, a dark IDE immediately looks polished. First impressions matter, even in code.&lt;/p&gt;




&lt;h2&gt;
  
  
  Dark Mode vs Light Mode: A Balanced Look
&lt;/h2&gt;

&lt;p&gt;This is one of those debates where both sides have real points. Here's an honest breakdown:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Situation&lt;/th&gt;
&lt;th&gt;Better Choice&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Long coding sessions at night&lt;/td&gt;
&lt;td&gt;Dark Mode ✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reading long documentation&lt;/td&gt;
&lt;td&gt;Light Mode ✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Working in a bright room or sunlight&lt;/td&gt;
&lt;td&gt;Light Mode ✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Working in a dim room or late hours&lt;/td&gt;
&lt;td&gt;Dark Mode ✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OLED laptop on battery&lt;/td&gt;
&lt;td&gt;Dark Mode ✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Users with certain visual impairments&lt;/td&gt;
&lt;td&gt;Light Mode ✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Screensharing code in presentations&lt;/td&gt;
&lt;td&gt;Dark Mode ✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Proofreading written content&lt;/td&gt;
&lt;td&gt;Light Mode ✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The honest truth? &lt;strong&gt;Neither is universally superior.&lt;/strong&gt; Dark mode wins in low-light coding environments. Light mode often wins for reading heavy text in bright conditions. Many experienced developers actually toggle between the two depending on context.&lt;/p&gt;




&lt;h2&gt;
  
  
  Best Tips for Dark Mode Users
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Choose your dark theme carefully.&lt;/strong&gt; Pure pitch black (&lt;code&gt;#000000&lt;/code&gt;) can actually create too much contrast with white text. Deep dark grays like &lt;code&gt;#1a1a2e&lt;/code&gt; or &lt;code&gt;#121212&lt;/code&gt; are often easier on the eyes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Match your terminal, editor, and browser&lt;/strong&gt; to the same dark theme family for a consistent, less jarring experience.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use a good font.&lt;/strong&gt; On dark backgrounds, fonts like JetBrains Mono, Fira Code, or Cascadia Code are legible and look clean.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enable OS-level dark mode&lt;/strong&gt; so your apps and system UI stay consistent, not just your IDE.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don't go full dark mode everywhere without thinking.&lt;/strong&gt; Some apps just aren't optimized for it and end up looking weird or broken.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adjust your screen brightness.&lt;/strong&gt; Dark mode doesn't mean you need max brightness. Tone it down — your eyes will thank you.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Common Mistakes Developers Make With Dark Mode
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Picking a theme that's all contrast, no comfort.&lt;/strong&gt;&lt;br&gt;
Maximum black with maximum white text looks sharp for screenshots but is brutal for 4-hour sessions. Find a theme that balances contrast with warmth. Popular ones like One Dark Pro, Dracula, and Tokyo Night are popular for a reason — they've been tuned over time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ignoring external lighting.&lt;/strong&gt;&lt;br&gt;
Dark mode helps most in low-light rooms. If you're working in a bright office, dark mode can actually make the screen harder to read because the ambient light creates glare on a dark surface.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Assuming dark mode fixes all eye strain.&lt;/strong&gt;&lt;br&gt;
Dark mode helps, but it doesn't replace proper habits. Take screen breaks. Follow the 20-20-20 rule (every 20 minutes, look at something 20 feet away for 20 seconds). Blink. Adjust your monitor height. No color scheme fixes poor ergonomics.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Forcing dark mode on every site using browser extensions.&lt;/strong&gt;&lt;br&gt;
Some websites are genuinely not built for dark mode. Forcing it can invert images, make colors muddy, or break layouts. Use it where it works natively when possible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Never trying light mode again.&lt;/strong&gt;&lt;br&gt;
If you've been on dark mode for years and always feel like reading documentation is painful — try switching to a clean light theme for a week. Sometimes the brain just needs a different kind of contrast for reading-heavy work.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Dark mode isn't just aesthetic rebellion or developer fashion. For many developers, it's a genuine comfort upgrade that reduces eye strain, extends battery life, improves focus, and makes code easier to read — especially during those long late-night sessions that are basically a rite of passage in this profession.&lt;/p&gt;

&lt;p&gt;That said, it's not a one-size-fits-all solution. Knowing when to use dark mode and when to switch is the real skill. The best developers stay flexible and optimize their environment for actual comfort, not just looks.&lt;/p&gt;

&lt;p&gt;If you're not on dark mode yet, give it a serious two-week trial with a well-designed theme like Dracula or One Dark Pro. If you are on dark mode — welcome to the club. You're in good company. 🌙&lt;/p&gt;




&lt;p&gt;Want to read more practical developer content like this? Head over to &lt;strong&gt;&lt;a href="https://hamidrazadev.com" rel="noopener noreferrer"&gt;hamidrazadev.com&lt;/a&gt;&lt;/strong&gt; for more articles, tips, and tutorials built for real developers.&lt;/p&gt;

&lt;p&gt;If this post helped you or made you think differently about your setup, share it with a dev friend who's still squinting at a white screen. 😊&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>productivity</category>
      <category>discuss</category>
    </item>
    <item>
      <title>What Is a CMS? A Friendly Guide for Beginners and Developers 🚀</title>
      <dc:creator>Muhammad Hamid Raza</dc:creator>
      <pubDate>Wed, 06 May 2026 10:52:03 +0000</pubDate>
      <link>https://dev.to/hamidrazadev/what-is-a-cms-a-friendly-guide-for-beginners-and-developers-ioh</link>
      <guid>https://dev.to/hamidrazadev/what-is-a-cms-a-friendly-guide-for-beginners-and-developers-ioh</guid>
      <description>&lt;p&gt;Ever tried updating a small typo on a website by editing raw HTML, and ended up breaking the entire layout? 😅 If yes, welcome to the club. That tiny moment of panic is exactly why CMS platforms exist.&lt;/p&gt;

&lt;p&gt;Today, websites are everywhere — blogs, online stores, school portals, news sites, portfolios. But not everyone wants to write code every time they need to add a blog post or update a banner. That's where a &lt;strong&gt;CMS&lt;/strong&gt; quietly saves the day.&lt;/p&gt;

&lt;p&gt;So let's break it down in plain English: what is a CMS, why do developers and non-developers love it, and when should you actually use one?&lt;/p&gt;




&lt;h2&gt;
  
  
  What Is a CMS?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;CMS&lt;/strong&gt; stands for &lt;strong&gt;Content Management System&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In simple words, a CMS is a software tool that helps you create, edit, organize, and publish content on a website — without needing to write code for every single change.&lt;/p&gt;

&lt;p&gt;Think of it like Google Docs, but for your website. You log in, type your content, click publish, and it appears online. The CMS handles the boring technical parts behind the scenes — storing your text, managing images, organizing pages, and showing them to visitors.&lt;/p&gt;

&lt;p&gt;A quick analogy for younger readers: imagine a school notice board. The principal doesn't rebuild the board every time there's a new notice. They just pin a new paper on it. A CMS is that notice board for your website. 📌&lt;/p&gt;

&lt;p&gt;Popular examples you may have heard of include &lt;strong&gt;WordPress&lt;/strong&gt;, &lt;strong&gt;Drupal&lt;/strong&gt;, &lt;strong&gt;Joomla&lt;/strong&gt;, &lt;strong&gt;Ghost&lt;/strong&gt;, &lt;strong&gt;Strapi&lt;/strong&gt;, &lt;strong&gt;Contentful&lt;/strong&gt;, and &lt;strong&gt;Sanity&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why a CMS Matters
&lt;/h2&gt;

&lt;p&gt;Here's the honest truth: most website owners are not developers. They are writers, teachers, shop owners, marketers, and small business folks who just want their content online.&lt;/p&gt;

&lt;p&gt;A CMS matters because it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lets non-technical people manage a website on their own.&lt;/li&gt;
&lt;li&gt;Saves developers from updating content manually every week.&lt;/li&gt;
&lt;li&gt;Speeds up website building since common features (login, comments, media library) come built-in.&lt;/li&gt;
&lt;li&gt;Keeps content organized in one place so nothing gets lost.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're a developer, a CMS frees you to focus on the fun parts — design, performance, custom features — instead of pushing tiny content updates for clients at midnight.&lt;/p&gt;

&lt;p&gt;And if you're a beginner learning web development, understanding CMS concepts is a huge career booster. A massive part of the web runs on CMS platforms, especially WordPress.&lt;/p&gt;




&lt;h2&gt;
  
  
  Benefits of Using a CMS (with Real Examples)
&lt;/h2&gt;

&lt;p&gt;Here are the real, practical benefits — not just buzzwords:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;No coding for everyday updates&lt;/strong&gt; 💡&lt;br&gt;&lt;br&gt;
Example: A bakery owner can add a new cake to the menu without calling a developer. They just log in, upload a photo, type the price, and click publish.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Built-in user roles&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Example: On a news website, editors can write articles, but only the admin can publish them. A CMS handles these permissions out of the box.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Media management made easy&lt;/strong&gt; 🖼️&lt;br&gt;&lt;br&gt;
Example: Uploading 50 product images becomes a drag-and-drop task instead of an FTP nightmare.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Templates and themes&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Example: A student building a portfolio can pick a clean theme in WordPress and have a working site in an afternoon.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Plugins and extensions&lt;/strong&gt; 🔧&lt;br&gt;&lt;br&gt;
Example: Want a contact form, SEO tools, or an online shop? Install a plugin instead of building it from scratch.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;SEO-friendly structure&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Example: Most CMS platforms generate clean URLs, sitemaps, and meta tags automatically, which helps your content show up on Google.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Scales with your needs&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Example: A personal blog can grow into a full magazine or e-commerce store without rebuilding the whole site.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Traditional CMS vs Headless CMS (Quick Comparison)
&lt;/h2&gt;

&lt;p&gt;This is one comparison that genuinely helps, especially for developers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Traditional CMS&lt;/strong&gt; (like WordPress)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Frontend and backend are tightly connected.&lt;/li&gt;
&lt;li&gt;Easier to set up for non-developers.&lt;/li&gt;
&lt;li&gt;Great for blogs, small business sites, and portfolios.&lt;/li&gt;
&lt;li&gt;Less flexible if you want to use modern frameworks like React or Next.js directly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Headless CMS&lt;/strong&gt; (like Strapi, Sanity, Contentful)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Only handles the backend (the content).&lt;/li&gt;
&lt;li&gt;You build the frontend with any framework you like.&lt;/li&gt;
&lt;li&gt;Perfect for apps, multi-platform projects (web + mobile), and modern stacks.&lt;/li&gt;
&lt;li&gt;Requires more developer involvement to set up.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Easy rule of thumb:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
If your client just wants a website, a traditional CMS is usually enough. If you're building a custom app or delivering content to multiple platforms, go headless. ⚡&lt;/p&gt;




&lt;h2&gt;
  
  
  Best Tips: Do's and Don'ts
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Do's ✅&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pick a CMS that matches your project's size. Don't use a hammer for a thumbtack.&lt;/li&gt;
&lt;li&gt;Keep your CMS and plugins updated to avoid security issues.&lt;/li&gt;
&lt;li&gt;Take regular backups. Future-you will thank present-you.&lt;/li&gt;
&lt;li&gt;Use strong passwords and two-factor authentication for admin accounts.&lt;/li&gt;
&lt;li&gt;Learn the basics of how the CMS stores data — it helps when something breaks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Don'ts ❌&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Don't install dozens of plugins "just in case." Each one adds weight and risk.&lt;/li&gt;
&lt;li&gt;Don't edit core CMS files directly. Updates will overwrite your changes.&lt;/li&gt;
&lt;li&gt;Don't ignore performance. A slow CMS site loses visitors fast.&lt;/li&gt;
&lt;li&gt;Don't pick a CMS just because it's trendy. Pick one that fits the project.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Common Mistakes People Make
&lt;/h2&gt;

&lt;p&gt;Even experienced developers slip up here. A few mistakes I see often:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Choosing the wrong CMS.&lt;/strong&gt; People grab WordPress for everything, even when a static site generator or headless CMS would be simpler and faster.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skipping security basics.&lt;/strong&gt; Default admin usernames, weak passwords, and outdated plugins are an open invitation for attackers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Overloading the site with plugins.&lt;/strong&gt; Each plugin is extra code running on your site. Too many plugins = slow site + more bugs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Forgetting backups.&lt;/strong&gt; One bad update can wipe out months of work. Backups are not optional.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ignoring the editor experience.&lt;/strong&gt; If your client struggles to add a blog post, the CMS setup failed — no matter how clean your code is.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These mistakes happen because CMS platforms feel "easy" at first, so people skip the planning step. A few minutes of thinking ahead saves days of fixing later.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;A CMS is simply a tool that makes managing website content easier for everyone — from a teenager starting their first blog to a full development team running a global news platform.&lt;/p&gt;

&lt;p&gt;If you're a beginner, start with something like WordPress to feel the magic of publishing without coding. If you're a developer, explore headless CMS options to combine clean backends with modern frontends. Either way, you're learning a skill the web genuinely runs on. 🌍&lt;/p&gt;

&lt;p&gt;If this guide helped clear things up, share it with a friend who's still scared of editing their website. And if you enjoyed the writing style, you'll find more friendly developer guides on &lt;strong&gt;&lt;a href="https://hamidrazadev.com" rel="noopener noreferrer"&gt;hamidrazadev.com&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Drop a comment with the CMS you use — I'm always curious to hear what works for other devs. 😊&lt;/p&gt;

&lt;p&gt;Happy building!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>beginners</category>
      <category>productivity</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Why DNS Was Introduced and How It Replaced Raw IP Addresses</title>
      <dc:creator>Muhammad Hamid Raza</dc:creator>
      <pubDate>Tue, 05 May 2026 08:57:35 +0000</pubDate>
      <link>https://dev.to/hamidrazadev/why-dns-was-introduced-and-how-it-replaced-raw-ip-addresses-3h0j</link>
      <guid>https://dev.to/hamidrazadev/why-dns-was-introduced-and-how-it-replaced-raw-ip-addresses-3h0j</guid>
      <description>&lt;p&gt;Have you ever wondered what actually happens when you type &lt;code&gt;google.com&lt;/code&gt; into your browser and press Enter? 🤔&lt;/p&gt;

&lt;p&gt;Behind the scenes, a quiet but brilliant system kicks into action — one that most people use thousands of times a day without ever thinking about it. That system is &lt;strong&gt;DNS&lt;/strong&gt;, the Domain Name System.&lt;/p&gt;

&lt;p&gt;Before DNS existed, accessing a website meant memorizing long strings of numbers. We're talking things like &lt;code&gt;192.168.1.1&lt;/code&gt; but for every single website on the internet. Sounds exhausting, right?&lt;/p&gt;

&lt;p&gt;This post explains why DNS was introduced, how it replaced raw IP addresses, and why understanding it makes you a sharper developer, a better debugger, and honestly just a more informed person on the internet.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Is an IP Address?
&lt;/h2&gt;

&lt;p&gt;Before we can appreciate DNS, we need to understand what it replaced.&lt;/p&gt;

&lt;p&gt;Every device connected to the internet — your laptop, your phone, the server hosting your favorite website — has an &lt;strong&gt;IP address&lt;/strong&gt;. Think of it like a home address. If you want to send a letter, you need to know where the house is. If your browser wants to load a website, it needs to know the server's address.&lt;/p&gt;

&lt;p&gt;An IPv4 address looks like this: &lt;code&gt;142.250.190.78&lt;/code&gt;&lt;br&gt;
An IPv6 address looks like this: &lt;code&gt;2607:f8b0:4004:c09::64&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;These numbers are how machines identify and talk to each other. Accurate? Yes. Human-friendly? Absolutely not.&lt;/p&gt;


&lt;h2&gt;
  
  
  What Is DNS?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;DNS stands for Domain Name System.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It is essentially the internet's phonebook. Instead of memorizing a number, you remember a name — like &lt;code&gt;google.com&lt;/code&gt; or &lt;code&gt;github.com&lt;/code&gt; — and DNS quietly translates that name into the correct IP address behind the scenes.&lt;/p&gt;

&lt;p&gt;Here is a simple analogy. Imagine you want to call your friend Ayesha. You don't memorize her phone number. You just search "Ayesha" in your contacts and your phone finds the number for you. DNS does exactly that — but for websites.&lt;/p&gt;

&lt;p&gt;You type a human-friendly name → DNS finds the IP address → your browser connects to the right server.&lt;/p&gt;

&lt;p&gt;Simple. Elegant. And completely invisible when it works correctly.&lt;/p&gt;


&lt;h2&gt;
  
  
  Why Was DNS Introduced? The Real Story
&lt;/h2&gt;

&lt;p&gt;DNS did not appear out of nowhere. It was born out of a very real and growing problem.&lt;/p&gt;
&lt;h3&gt;
  
  
  The Early Internet and the HOSTS.TXT File
&lt;/h3&gt;

&lt;p&gt;In the early days of the internet (the ARPANET era, late 1960s to early 1980s), the network was tiny. There were only a few hundred computers connected to it — mostly at universities and research labs.&lt;/p&gt;

&lt;p&gt;Back then, every computer had a file called &lt;code&gt;HOSTS.TXT&lt;/code&gt;. This plain text file listed every hostname and its matching IP address on the entire network.&lt;/p&gt;

&lt;p&gt;It looked something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;192.0.0.1    stanford
192.0.0.2    mit
192.0.0.3    ucla
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you wanted to connect to another machine, your computer looked up the name in this file and got the IP. Simple enough — when the internet was small.&lt;/p&gt;

&lt;p&gt;There was one central copy of &lt;code&gt;HOSTS.TXT&lt;/code&gt; maintained by Stanford Research Institute. Every network connected to ARPANET would download this file periodically to stay updated.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Problem That Made HOSTS.TXT Impossible to Scale
&lt;/h3&gt;

&lt;p&gt;As the internet grew through the late 1970s and early 1980s, this system started to break down fast. Here is why:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The file grew too large.&lt;/strong&gt; With hundreds and then thousands of machines, HOSTS.TXT became huge and slow to process.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Updates were too slow.&lt;/strong&gt; It took days for changes to spread across the network. New hostnames would not appear immediately everywhere.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Name conflicts were a nightmare.&lt;/strong&gt; Two organizations might register the same hostname because there was no central authority to prevent it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bandwidth was being wasted.&lt;/strong&gt; Every machine had to download the full file constantly to stay current.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Human memory still had limits.&lt;/strong&gt; Even with the file doing the lookup, administrators had to manage it manually.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The internet was growing, and HOSTS.TXT simply could not keep up.&lt;/p&gt;

&lt;h3&gt;
  
  
  Enter Paul Mockapetris
&lt;/h3&gt;

&lt;p&gt;In &lt;strong&gt;1983&lt;/strong&gt;, computer scientist &lt;strong&gt;Paul Mockapetris&lt;/strong&gt; designed and published the DNS specification in &lt;strong&gt;RFC 882 and RFC 883&lt;/strong&gt;. His solution was both smart and scalable.&lt;/p&gt;

&lt;p&gt;Instead of one giant file maintained in one place, DNS would be a &lt;strong&gt;distributed, hierarchical database&lt;/strong&gt; spread across thousands of servers around the world. No single server would know everything. But together, they would be able to answer any hostname query on the planet.&lt;/p&gt;

&lt;p&gt;This was the turning point. DNS replaced HOSTS.TXT, and it has been running the internet ever since.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Matters for Developers
&lt;/h2&gt;

&lt;p&gt;You might be thinking, "Okay, interesting history — but why should I care as a developer?"&lt;/p&gt;

&lt;p&gt;Fair question. Here is why DNS knowledge is actually useful day-to-day:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Debugging Network Issues
&lt;/h3&gt;

&lt;p&gt;When your app cannot connect to an external API or your domain is not loading, DNS is often the first thing to check. Understanding how DNS works helps you debug faster instead of staring blankly at a timeout error.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Deploying Apps and Configuring Domains
&lt;/h3&gt;

&lt;p&gt;When you deploy a Next.js app to Vercel or a server on DigitalOcean, you always have to update DNS records — &lt;code&gt;A records&lt;/code&gt;, &lt;code&gt;CNAME records&lt;/code&gt;, &lt;code&gt;TXT records&lt;/code&gt;. Knowing what these mean saves you hours of confusion.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Setting Up Email
&lt;/h3&gt;

&lt;p&gt;Configuring a custom email domain requires DNS records like &lt;code&gt;MX&lt;/code&gt; and &lt;code&gt;SPF&lt;/code&gt;. Without understanding DNS basics, this feels like dark magic.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Performance and Caching
&lt;/h3&gt;

&lt;p&gt;DNS responses are cached for a period defined by &lt;strong&gt;TTL (Time to Live)&lt;/strong&gt;. If you update a DNS record and it does not take effect immediately, that is TTL doing its job. Knowing this prevents unnecessary panic.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Security
&lt;/h3&gt;

&lt;p&gt;DNS-based attacks like &lt;strong&gt;DNS spoofing&lt;/strong&gt; and &lt;strong&gt;DNS hijacking&lt;/strong&gt; are real threats. Developers and sysadmins who understand DNS are better equipped to protect their infrastructure.&lt;/p&gt;




&lt;h2&gt;
  
  
  How DNS Actually Works: A Step-by-Step Breakdown
&lt;/h2&gt;

&lt;p&gt;Let's trace what happens when you type &lt;code&gt;hamidrazadev.com&lt;/code&gt; into your browser.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1 — Check the local cache&lt;/strong&gt;&lt;br&gt;
Your browser first checks if it has recently resolved this domain. If yes, it uses the cached IP and skips the rest.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2 — Ask the Recursive Resolver&lt;/strong&gt;&lt;br&gt;
If not cached, your device contacts a &lt;strong&gt;recursive resolver&lt;/strong&gt; — usually provided by your ISP or a public DNS service like &lt;code&gt;8.8.8.8&lt;/code&gt; (Google) or &lt;code&gt;1.1.1.1&lt;/code&gt; (Cloudflare).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3 — Ask the Root Name Server&lt;/strong&gt;&lt;br&gt;
The resolver asks a &lt;strong&gt;Root Name Server&lt;/strong&gt; where to find information about &lt;code&gt;.com&lt;/code&gt; domains. There are 13 root server clusters around the world (operated by organizations like ICANN, NASA, and Verisign).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4 — Ask the TLD Name Server&lt;/strong&gt;&lt;br&gt;
The root server points the resolver to the &lt;strong&gt;TLD (Top-Level Domain) Name Server&lt;/strong&gt; responsible for &lt;code&gt;.com&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 5 — Ask the Authoritative Name Server&lt;/strong&gt;&lt;br&gt;
The TLD server points to the &lt;strong&gt;Authoritative Name Server&lt;/strong&gt; for &lt;code&gt;hamidrazadev.com&lt;/code&gt; specifically — this is the server that actually knows the IP address.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 6 — Get the IP address&lt;/strong&gt;&lt;br&gt;
The authoritative server returns the IP address. The resolver caches it and sends it to your browser.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 7 — Your browser connects&lt;/strong&gt;&lt;br&gt;
Your browser now has the IP address and makes a request to the server. The website loads. 🚀&lt;/p&gt;

&lt;p&gt;This entire process typically completes in &lt;strong&gt;milliseconds&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  DNS vs. Raw IP Addresses: A Quick Comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Raw IP Address&lt;/th&gt;
&lt;th&gt;DNS&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Human-readable&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;td&gt;✅ Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Easy to remember&lt;/td&gt;
&lt;td&gt;❌ Very hard&lt;/td&gt;
&lt;td&gt;✅ Simple names&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scales with internet growth&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;td&gt;✅ Distributed system&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Supports changes&lt;/td&gt;
&lt;td&gt;❌ Hard to update&lt;/td&gt;
&lt;td&gt;✅ Update DNS records anytime&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Required for email/SSL setup&lt;/td&gt;
&lt;td&gt;❌ Insufficient&lt;/td&gt;
&lt;td&gt;✅ Essential&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Using raw IPs still works in certain scenarios — like internal networks or hardcoded server calls. But for public-facing services, DNS is non-negotiable.&lt;/p&gt;




&lt;h2&gt;
  
  
  Common DNS Record Types You Should Know
&lt;/h2&gt;

&lt;p&gt;Here is a quick reference for the records developers deal with most often:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A Record&lt;/strong&gt; — Maps a domain to an IPv4 address. This is the most common record.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AAAA Record&lt;/strong&gt; — Maps a domain to an IPv6 address.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CNAME Record&lt;/strong&gt; — Points one domain to another domain (alias). Used a lot in Vercel and Netlify deployments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MX Record&lt;/strong&gt; — Specifies the mail server for a domain. Needed for email.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TXT Record&lt;/strong&gt; — Stores arbitrary text. Used for domain verification and SPF/DKIM email authentication.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NS Record&lt;/strong&gt; — Identifies which name servers are authoritative for a domain.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Best Tips for Working with DNS
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;✅ Do's&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Lower your TTL before making changes.&lt;/strong&gt; Before you update a DNS record, lower the TTL to something like 300 seconds (5 minutes). This makes changes propagate faster. Once stable, you can raise it back.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use a reliable DNS provider.&lt;/strong&gt; Cloudflare DNS (&lt;code&gt;1.1.1.1&lt;/code&gt;) and Google DNS (&lt;code&gt;8.8.8.8&lt;/code&gt;) are fast and trustworthy for resolvers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use &lt;code&gt;nslookup&lt;/code&gt; or &lt;code&gt;dig&lt;/code&gt; to debug.&lt;/strong&gt; These command-line tools let you query DNS directly and are invaluable for troubleshooting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Document your DNS records.&lt;/strong&gt; Keep a simple spreadsheet or note of what each record does. Future-you will thank present-you.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;❌ Don'ts&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Don't expect instant propagation.&lt;/strong&gt; DNS changes take time to spread globally — sometimes minutes, sometimes up to 48 hours depending on TTL values.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don't delete records without checking dependencies.&lt;/strong&gt; Removing an &lt;code&gt;MX record&lt;/code&gt; will break your email. Removing a &lt;code&gt;CNAME&lt;/code&gt; might break your subdomain.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don't rely on IP addresses directly in production configs.&lt;/strong&gt; If the server IP changes (which happens), you will have to update every hardcoded reference. Use domain names instead.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Common Mistakes People Make with DNS
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Mistake 1: Panicking when changes don't apply immediately
&lt;/h3&gt;

&lt;p&gt;DNS propagation is not instant. When you update a record and it doesn't work right away, that's normal. Wait for the TTL to expire. Use tools like &lt;a href="https://www.whatsmydns.net" rel="noopener noreferrer"&gt;whatsmydns.net&lt;/a&gt; to track propagation globally.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mistake 2: Forgetting to renew a domain
&lt;/h3&gt;

&lt;p&gt;Your domain is registered, not owned forever. When it expires, your DNS stops working and someone else can register it. Set auto-renewal and use a real email for domain alerts.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mistake 3: Confusing CNAME and A records
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;CNAME&lt;/strong&gt; points to another domain name. An &lt;strong&gt;A record&lt;/strong&gt; points to an IP address. Using a CNAME where an A record is needed (or vice versa) is a classic setup mistake that causes hours of confusion.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mistake 4: Setting TTL too high during migration
&lt;/h3&gt;

&lt;p&gt;If you are moving a website to a new server and your TTL is set to 86400 (24 hours), visitors may keep hitting the old server for an entire day. Always lower TTL in advance before migrations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mistake 5: Not testing locally before going live
&lt;/h3&gt;

&lt;p&gt;Use &lt;code&gt;dig&lt;/code&gt; or &lt;code&gt;nslookup&lt;/code&gt; to confirm your DNS is pointing where you think it is before announcing a new deployment to the world.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;DNS is one of those technologies that works so silently and reliably that most people forget it exists — until it breaks. 😄&lt;/p&gt;

&lt;p&gt;What started as a simple text file on a handful of computers in the early internet became a distributed, global system that handles billions of queries every single day. It replaced raw IP addresses not by eliminating them, but by making them invisible to humans — and that invisibility is the point.&lt;/p&gt;

&lt;p&gt;For developers, understanding DNS is not just academic knowledge. It is a practical skill that shows up in deployments, debugging sessions, email setups, domain migrations, and security decisions. The more comfortable you are with it, the less mysterious the internet becomes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The big takeaway:&lt;/strong&gt; IP addresses are how machines talk. DNS is how humans stay sane while that's happening.&lt;/p&gt;




&lt;p&gt;If you found this post helpful, feel free to share it with a fellow developer or student who is just starting to explore how the internet works. 😊&lt;/p&gt;

&lt;p&gt;For more developer content, tutorials, and deep dives like this one, visit &lt;strong&gt;&lt;a href="https://hamidrazadev.com" rel="noopener noreferrer"&gt;hamidrazadev.com&lt;/a&gt;&lt;/strong&gt; — new posts go up regularly and cover topics from frontend development to networking concepts like this one.&lt;/p&gt;

&lt;p&gt;Drop a comment if you have questions, or share this post if it cleared something up for you. Happy coding! 🚀&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>networking</category>
      <category>devops</category>
      <category>beginners</category>
    </item>
    <item>
      <title>VS Code 1.118 Is Here — And It's All About Smarter Agents, Faster Code, and Less Token Waste</title>
      <dc:creator>Muhammad Hamid Raza</dc:creator>
      <pubDate>Mon, 04 May 2026 13:42:55 +0000</pubDate>
      <link>https://dev.to/hamidrazadev/vs-code-1118-is-here-and-its-all-about-smarter-agents-faster-code-and-less-token-waste-pj9</link>
      <guid>https://dev.to/hamidrazadev/vs-code-1118-is-here-and-its-all-about-smarter-agents-faster-code-and-less-token-waste-pj9</guid>
      <description>&lt;p&gt;You updated VS Code, glanced at the changelog, and thought, &lt;em&gt;"Cool, more Copilot stuff."&lt;/em&gt; Then you closed it and moved on.&lt;/p&gt;

&lt;p&gt;But wait — this release is actually worth a proper look. 👀&lt;/p&gt;

&lt;p&gt;VS Code &lt;strong&gt;1.118&lt;/strong&gt; (released April 29, 2026) is packed with features that genuinely change how you work with AI agents, search your codebase, manage chat history, and even keep your token usage from quietly draining your budget. Whether you're using Copilot daily or just exploring AI-assisted coding, there's something real here for you.&lt;/p&gt;

&lt;p&gt;So let's break it down in plain English — no corporate fluff, just the stuff that matters.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Is VS Code 1.118?
&lt;/h2&gt;

&lt;p&gt;VS Code 1.118 is the latest monthly release of Visual Studio Code — Microsoft's free, open-source code editor that millions of developers use every day.&lt;/p&gt;

&lt;p&gt;Each release ships new features, bug fixes, and improvements. This one focuses heavily on the &lt;strong&gt;agent experience&lt;/strong&gt;, which basically means making Copilot smarter, faster, and cheaper to run.&lt;/p&gt;

&lt;p&gt;If you're not familiar with agents: think of them as AI that doesn't just answer questions — they &lt;em&gt;act&lt;/em&gt;. They write code, run terminal commands, search your files, and loop through tasks until the job is done. This release makes all of that smoother and more efficient.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Release Matters
&lt;/h2&gt;

&lt;p&gt;Here's the honest truth: AI-assisted coding is no longer a gimmick. It's becoming part of the daily workflow for a lot of developers.&lt;/p&gt;

&lt;p&gt;But more AI usage means more tokens. More tokens means higher costs — especially now that GitHub announced Copilot is moving to &lt;strong&gt;usage-based billing on June 1, 2026&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;VS Code 1.118 directly addresses this. The team made serious engineering improvements to reduce how many tokens each request uses, without making Copilot worse. That's a meaningful change for anyone who relies on it.&lt;/p&gt;

&lt;p&gt;Beyond cost, this release also:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Makes it easier to search across massive codebases&lt;/li&gt;
&lt;li&gt;Lets you control Copilot sessions &lt;em&gt;remotely&lt;/em&gt;, from your phone&lt;/li&gt;
&lt;li&gt;Helps you revisit your chat history like a dev journal&lt;/li&gt;
&lt;li&gt;Brings TypeScript 7 one step closer to everyone&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's not a small update. That's a solid month of real improvements.&lt;/p&gt;




&lt;h2&gt;
  
  
  Key Features with Real-Life Examples
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🚀 Remote Control for Copilot CLI Sessions
&lt;/h3&gt;

&lt;p&gt;Imagine you kick off a long agent task before lunch. While you're away, it hits a decision point and stops. Previously, you'd have to be back at your machine to continue.&lt;/p&gt;

&lt;p&gt;With &lt;strong&gt;remote control&lt;/strong&gt;, you can approve, steer, or check progress from your phone using the GitHub mobile app — while the session keeps running on your machine in the background.&lt;/p&gt;

&lt;p&gt;Enable it with the &lt;code&gt;github.copilot.chat.cli.remote.enabled&lt;/code&gt; setting and type &lt;code&gt;/remote on&lt;/code&gt; in a Copilot CLI chat to get started.&lt;/p&gt;




&lt;h3&gt;
  
  
  🔍 Semantic Indexing for &lt;em&gt;All&lt;/em&gt; Workspaces
&lt;/h3&gt;

&lt;p&gt;Before 1.118, semantic search (which lets Copilot find code by &lt;em&gt;meaning&lt;/em&gt;, not just exact words) only worked with GitHub or Azure DevOps repos.&lt;/p&gt;

&lt;p&gt;Now it works for &lt;strong&gt;any workspace&lt;/strong&gt;. So if you ask Copilot "where do we handle user authentication?", it can find code with terms like &lt;code&gt;signIn&lt;/code&gt;, &lt;code&gt;verifyCredentials&lt;/code&gt;, or &lt;code&gt;OAuth token exchange&lt;/code&gt; — even if the word "authentication" never appears.&lt;/p&gt;

&lt;p&gt;For local projects, it might take a few minutes to build the index initially. But once it's ready, Copilot understands your codebase much better.&lt;/p&gt;




&lt;h3&gt;
  
  
  💡 GitHub Text Search Across Repos and Orgs
&lt;/h3&gt;

&lt;p&gt;Semantic search is great for fuzzy intent. But sometimes you need an &lt;strong&gt;exact match&lt;/strong&gt; — like finding a specific error message or API name across your entire organization's codebase.&lt;/p&gt;

&lt;p&gt;The new &lt;code&gt;githubTextSearch&lt;/code&gt; agent tool does a grep-style search across any GitHub repo or organization, giving Copilot a much sharper way to look things up outside your current workspace.&lt;/p&gt;




&lt;h3&gt;
  
  
  ⚡ Massive Token Efficiency Improvements
&lt;/h3&gt;

&lt;p&gt;This is the one that affects your wallet directly. The team rolled out several changes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cache reuse across turns:&lt;/strong&gt; Over 93% of each request is now served from cache in active agent sessions. For Anthropic models, cached tokens cost roughly 10x less.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tool search tool:&lt;/strong&gt; Instead of loading every possible tool schema on every request, VS Code now loads a small core set and fetches the rest only when needed. This alone saves up to &lt;strong&gt;20% in token usage&lt;/strong&gt; for Claude Sonnet 4.5+ users.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agentic search and execution tools:&lt;/strong&gt; Powered by smaller, cheaper models that handle specific tasks like codebase exploration and terminal commands. Early results show up to &lt;strong&gt;20% additional token savings&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of this changes how Copilot behaves — it just makes it cheaper to run.&lt;/p&gt;




&lt;h3&gt;
  
  
  📋 Chronicle — Your Chat History as a Dev Journal (Experimental)
&lt;/h3&gt;

&lt;p&gt;Ever tried to write a standup report and completely blanked on what you did yesterday?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Chronicle&lt;/strong&gt; tracks your Copilot chat sessions in a local SQLite database — recording which files you touched, which PRs you referenced, and what you were working on. Then you can ask it things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;/chronicle:standup&lt;/code&gt; → Generates a standup report from the last 24 hours&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/chronicle:tips&lt;/code&gt; → Gives you personalized prompting tips based on your usage&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/chronicle what files did I edit yesterday?&lt;/code&gt; → Free-form natural language queries&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Enable it with &lt;code&gt;github.copilot.chat.localIndex.enabled&lt;/code&gt;. It's experimental, but genuinely useful.&lt;/p&gt;




&lt;h3&gt;
  
  
  🛠️ TypeScript 7.0 Beta Support
&lt;/h3&gt;

&lt;p&gt;TypeScript 7 is a full rewrite in native code. The performance difference is wild — VS Code's own build time dropped from &lt;strong&gt;60 seconds to 10 seconds&lt;/strong&gt; just by switching to TS 7 for type checking.&lt;/p&gt;

&lt;p&gt;You can try it today by installing the &lt;strong&gt;TypeScript Native preview extension&lt;/strong&gt;. It's still beta, so it's not for production, but it's worth testing.&lt;/p&gt;




&lt;h3&gt;
  
  
  🖥️ VS Code Agents App (Insiders)
&lt;/h3&gt;

&lt;p&gt;If you're on VS Code Insiders, the Agents app now integrates more tightly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Launch it directly from the title bar&lt;/li&gt;
&lt;li&gt;Access it from the browser at &lt;code&gt;insiders.vscode.dev/agents&lt;/code&gt; (requires a Dev Tunnel)&lt;/li&gt;
&lt;li&gt;Use the &lt;strong&gt;Claude Agent&lt;/strong&gt; alongside Copilot and other agents&lt;/li&gt;
&lt;li&gt;Tabs persist across sessions, so your browser doesn't refresh when you switch context&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's still in preview, but it's shaping up into a genuinely useful parallel workflow tool.&lt;/p&gt;




&lt;h2&gt;
  
  
  Before vs. After: How Token Usage Has Changed
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Area&lt;/th&gt;
&lt;th&gt;Before 1.118&lt;/th&gt;
&lt;th&gt;After 1.118&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cache reuse per request&lt;/td&gt;
&lt;td&gt;Variable&lt;/td&gt;
&lt;td&gt;93%+ in active sessions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tool schema loading&lt;/td&gt;
&lt;td&gt;All tools every turn&lt;/td&gt;
&lt;td&gt;Core set + on-demand loading&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Terminal command handling&lt;/td&gt;
&lt;td&gt;Main model&lt;/td&gt;
&lt;td&gt;Smaller, dedicated execution tool&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Codebase search&lt;/td&gt;
&lt;td&gt;Main model&lt;/td&gt;
&lt;td&gt;Smaller, dedicated search tool&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Estimated token savings&lt;/td&gt;
&lt;td&gt;Baseline&lt;/td&gt;
&lt;td&gt;Up to ~20-40% in agent workflows&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This doesn't mean Copilot suddenly becomes free — but for heavy users, the cumulative difference will be noticeable.&lt;/p&gt;




&lt;h2&gt;
  
  
  Best Tips for Getting the Most Out of VS Code 1.118
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;✅ Do:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enable &lt;code&gt;github.copilot.chat.localIndex.enabled&lt;/code&gt; to try Chronicle — your future self will thank you at standup&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;Build Codebase semantic index&lt;/code&gt; manually if Copilot seems off on local projects&lt;/li&gt;
&lt;li&gt;Try &lt;code&gt;/remote on&lt;/code&gt; in Copilot CLI before leaving your desk for long agent tasks&lt;/li&gt;
&lt;li&gt;Install the TypeScript Native preview extension in a non-production project to test TS 7 performance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;❌ Don't:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Expect remote control to work without enabling the &lt;code&gt;github.copilot.chat.cli.remote.enabled&lt;/code&gt; setting first&lt;/li&gt;
&lt;li&gt;Assume TS 7 is production-ready — it's still beta&lt;/li&gt;
&lt;li&gt;Ignore the Chronicle feature just because it's experimental; it's genuinely useful for tracking work&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Common Mistakes to Avoid
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Skipping experimental features entirely.&lt;/strong&gt; A lot of the best stuff in 1.118 is behind experimental flags. That's not a warning sign — it's a chance to try genuinely useful features before they're stable. Just use them in non-critical projects first.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Forgetting to build the semantic index.&lt;/strong&gt; If you're on a local workspace (not GitHub/ADO), Copilot won't have semantic search until the index is ready. Run the build command manually if you want it available right away.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ignoring the token efficiency changes.&lt;/strong&gt; If you're on a usage-based plan, these improvements aren't just nice to have — they affect your bill. Make sure you're on Claude Sonnet 4.5+ or GPT-5.4/5.5 to benefit from the tool search savings.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Not checking for updates manually.&lt;/strong&gt; VS Code 1.118 is rolling out gradually. If you haven't seen it yet, go to &lt;strong&gt;Help → Check for Updates&lt;/strong&gt; to get it right away.&lt;/p&gt;




&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;VS Code 1.118 is a focused, well-executed release. It doesn't add flashy gimmicks — it makes the AI-assisted workflow more reliable, more efficient, and cheaper to run.&lt;/p&gt;

&lt;p&gt;Remote control for CLI sessions, semantic search everywhere, Chronicle for tracking your work, and serious token savings across the board — these are practical improvements that affect your daily workflow.&lt;/p&gt;

&lt;p&gt;If you're a developer who uses Copilot regularly, this update is worth enabling the experimental features and exploring properly.&lt;/p&gt;

&lt;p&gt;Check for the update, enable Chronicle, test the remote control — and enjoy paying a little less in token costs. 🎉&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Want more VS Code breakdowns, dev tools, and web development content? Head over to *&lt;/em&gt;&lt;a href="https://hamidrazadev.com" rel="noopener noreferrer"&gt;hamidrazadev.com&lt;/a&gt;** for more practical articles written by a developer, for developers.*&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If this post saved you time or taught you something new, share it with your team or drop a comment below — it helps more than you know. 🙌&lt;/em&gt;&lt;/p&gt;

</description>
      <category>vscode</category>
      <category>typescript</category>
      <category>webdev</category>
      <category>ai</category>
    </item>
    <item>
      <title>WiFi vs Cellular Data: Why WiFi Often Wins for Daily Internet Use 🌐</title>
      <dc:creator>Muhammad Hamid Raza</dc:creator>
      <pubDate>Mon, 04 May 2026 10:26:25 +0000</pubDate>
      <link>https://dev.to/hamidrazadev/wifi-vs-cellular-data-why-wifi-often-wins-for-daily-internet-use-2g49</link>
      <guid>https://dev.to/hamidrazadev/wifi-vs-cellular-data-why-wifi-often-wins-for-daily-internet-use-2g49</guid>
      <description>&lt;p&gt;We've all been there. You're downloading a big update, watching a tutorial, or pushing code to GitHub, and suddenly your mobile data vanishes faster than free pizza at a developer meetup. 🍕&lt;/p&gt;

&lt;p&gt;Then you connect to WiFi, and everything just… works. Smoother. Faster. No panic about your data balance.&lt;/p&gt;

&lt;p&gt;But why does WiFi usually feel better than cellular data? Is it always the right choice? And when should you actually stick with mobile data instead?&lt;/p&gt;

&lt;p&gt;Let's break it down in simple words, without any tech-jargon overload. Ready to finally understand the difference?&lt;/p&gt;




&lt;h2&gt;
  
  
  What Is WiFi and What Is Cellular Data?
&lt;/h2&gt;

&lt;p&gt;Before we compare them, let's keep things super simple.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;WiFi&lt;/strong&gt; is internet that comes from a nearby router. The router is connected to a wired internet line (fiber, cable, DSL, or similar), and it shares that connection wirelessly with devices around it, usually inside a home, office, café, or airport.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cellular data&lt;/strong&gt; is internet that comes from mobile network towers. Your SIM card connects your phone to those towers, and the tower sends data to your device through radio signals. This is what powers 3G, 4G LTE, and 5G.&lt;/p&gt;

&lt;p&gt;Think of it like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;WiFi is like drinking water from a tap at home. 🚰&lt;/li&gt;
&lt;li&gt;Cellular data is like buying bottled water on the go. 💧&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both give you water. But one is cheaper at home, and the other is convenient when you're traveling.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Topic Matters
&lt;/h2&gt;

&lt;p&gt;Internet is no longer optional. It's how we learn, work, build apps, attend meetings, watch tutorials, and stay connected with people we care about.&lt;/p&gt;

&lt;p&gt;For developers and students, the choice between WiFi and cellular data affects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How much money you spend each month&lt;/li&gt;
&lt;li&gt;How fast you can download tools, packages, and updates&lt;/li&gt;
&lt;li&gt;Whether your video calls freeze during a client demo&lt;/li&gt;
&lt;li&gt;How safely you connect to the internet&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A small choice, but a big impact on your daily routine.&lt;/p&gt;

&lt;p&gt;So the question is simple: &lt;strong&gt;why do most people prefer WiFi when it's available?&lt;/strong&gt; Let's get into the real reasons.&lt;/p&gt;




&lt;h2&gt;
  
  
  Benefits of WiFi Over Cellular Data (with Real-Life Examples)
&lt;/h2&gt;

&lt;p&gt;Here are the practical reasons WiFi often beats cellular data for most everyday tasks.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Usually Cheaper for Heavy Use 💰
&lt;/h3&gt;

&lt;p&gt;Most home and office WiFi plans are unlimited or have very high data limits. Cellular plans, especially prepaid ones, often charge more per GB.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; Downloading a 5 GB Android Studio update on mobile data could eat your whole weekly package. On WiFi, it's just… a download.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Better for Large Downloads and Uploads
&lt;/h3&gt;

&lt;p&gt;Pushing a Docker image, cloning a big repo, or uploading video content? WiFi is usually more comfortable for that kind of work because routers are built to handle long, heavy sessions without throttling.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; A YouTuber uploading a 4K video will almost always pick WiFi to avoid burning through their mobile data plan.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. More Stable for Video Calls and Meetings
&lt;/h3&gt;

&lt;p&gt;WiFi tends to give a steadier connection inside buildings where cellular signals can drop. If your office is on the 7th floor with thick walls, mobile signals might struggle, but the WiFi router right next to you won't.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; During a Zoom standup, WiFi often keeps your video sharp while cellular data can get jittery indoors.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Multiple Devices, One Connection
&lt;/h3&gt;

&lt;p&gt;A single WiFi router can serve your laptop, phone, tablet, smart TV, and even your smart bulb at the same time. With cellular data, every SIM is a separate plan (unless you use hotspot, which drains your phone battery fast).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; A family of four streaming, gaming, and working from home on a single WiFi plan is much cheaper than four separate mobile data plans.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. No Stress About Daily or Monthly Limits
&lt;/h3&gt;

&lt;p&gt;Many cellular packages have strict caps. Once you cross them, speed drops or extra charges kick in. Most home WiFi plans either don't have limits or have very generous ones.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; Binge-watching a coding course on Udemy at night? WiFi handles it without sweat.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Often Faster Where Coverage Is Weak
&lt;/h3&gt;

&lt;p&gt;If you live in an area with weak mobile signal, WiFi (powered by a wired connection) can give you better speeds than cellular ever could in that location.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Better Battery Life
&lt;/h3&gt;

&lt;p&gt;This one surprises many people. Phones generally use &lt;strong&gt;less battery on WiFi than on cellular&lt;/strong&gt;, especially when the cellular signal is weak and the phone is constantly searching for a tower.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; Ever notice your phone heats up and drains fast in low-signal areas? That's your phone working overtime to stay connected.&lt;/p&gt;




&lt;h2&gt;
  
  
  WiFi vs Cellular Data: A Quick Comparison
&lt;/h2&gt;

&lt;p&gt;Both have their place. Here's an honest, balanced look.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;WiFi&lt;/th&gt;
&lt;th&gt;Cellular Data&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cost for heavy use&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Usually cheaper&lt;/td&gt;
&lt;td&gt;Often more expensive per GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Mobility&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Works in a fixed area&lt;/td&gt;
&lt;td&gt;Works almost anywhere with signal&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Speed&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Depends on the router and plan&lt;/td&gt;
&lt;td&gt;Depends on tower, network, and location&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Stability indoors&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Generally better&lt;/td&gt;
&lt;td&gt;Can drop behind walls&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Setup needed&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Router required&lt;/td&gt;
&lt;td&gt;Just a SIM and signal&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Security&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Safer on private networks, risky on public ones&lt;/td&gt;
&lt;td&gt;Generally encrypted by the carrier&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Battery use&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Lower&lt;/td&gt;
&lt;td&gt;Higher, especially on weak signal&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Best for&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Home, office, study, big downloads&lt;/td&gt;
&lt;td&gt;Travel, commute, emergencies, outdoors&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;So WiFi isn't &lt;em&gt;always&lt;/em&gt; better. It's better &lt;strong&gt;for the right situation&lt;/strong&gt;, which is usually most of our day.&lt;/p&gt;




&lt;h2&gt;
  
  
  Pros and Cons in Plain Words
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Pros of WiFi
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Cheaper for heavy and long usage&lt;/li&gt;
&lt;li&gt;More stable for indoor work&lt;/li&gt;
&lt;li&gt;Supports many devices at once&lt;/li&gt;
&lt;li&gt;Lower battery drain&lt;/li&gt;
&lt;li&gt;Great for big downloads and video calls&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cons of WiFi
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Tied to one location (you can't take your home router to the park)&lt;/li&gt;
&lt;li&gt;Public WiFi can be unsafe without a VPN&lt;/li&gt;
&lt;li&gt;Needs hardware (router, modem) and setup&lt;/li&gt;
&lt;li&gt;If the router or internet line fails, the whole network goes down&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pros of Cellular Data
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Works almost anywhere with signal&lt;/li&gt;
&lt;li&gt;No setup, just insert a SIM&lt;/li&gt;
&lt;li&gt;Good for travel, road trips, and outdoor work&lt;/li&gt;
&lt;li&gt;Useful as a backup when WiFi fails&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cons of Cellular Data
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Usually pricier per GB&lt;/li&gt;
&lt;li&gt;Speeds can drop during peak hours or in crowded areas&lt;/li&gt;
&lt;li&gt;Drains battery faster&lt;/li&gt;
&lt;li&gt;Hits data caps quickly with heavy usage&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The honest truth? Most people don't have to pick one. They use &lt;strong&gt;WiFi at home and work, and cellular data on the move&lt;/strong&gt;. That combo wins almost every time.&lt;/p&gt;




&lt;h2&gt;
  
  
  Best Tips and Practical Do's &amp;amp; Don'ts
&lt;/h2&gt;

&lt;p&gt;A few habits I've personally found useful as a developer:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use WiFi for big tasks: OS updates, IDE downloads, package installs, Docker pulls, and Zoom calls.&lt;/li&gt;
&lt;li&gt;Keep mobile data on standby for when WiFi fails (which always happens 5 minutes before a deadline 😅).&lt;/li&gt;
&lt;li&gt;Use a &lt;strong&gt;VPN on public WiFi&lt;/strong&gt;, especially in airports, cafés, and hotels.&lt;/li&gt;
&lt;li&gt;Set "WiFi only" mode for app updates, cloud backups, and large media downloads.&lt;/li&gt;
&lt;li&gt;Restart your router every few weeks. It really does help.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Don't:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Don't log into banking or work accounts on &lt;strong&gt;open public WiFi&lt;/strong&gt; without a VPN.&lt;/li&gt;
&lt;li&gt;Don't waste mobile data on auto-playing videos. Turn off autoplay in YouTube, Instagram, and similar apps.&lt;/li&gt;
&lt;li&gt;Don't stand right next to the microwave while complaining about slow WiFi. (Yes, microwaves can interfere with 2.4 GHz networks.) 🔧&lt;/li&gt;
&lt;li&gt;Don't forget to turn off your hotspot. It silently drains your phone for hours.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Common Mistakes People Make
&lt;/h2&gt;

&lt;p&gt;Even tech-savvy folks slip up here. A few I see often:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Trusting any "Free WiFi" sign.&lt;/strong&gt;&lt;br&gt;
Free WiFi is great, but some networks are set up to capture data. If the network has no password and no login page from a known brand, be careful.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Forgetting that "Unlimited" isn't always unlimited.&lt;/strong&gt;&lt;br&gt;
Many cellular "unlimited" plans slow you down after a certain amount of data. Read the fine print before relying on it for work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Using mobile hotspot as a long-term solution.&lt;/strong&gt;&lt;br&gt;
Hotspot is a lifesaver in emergencies, but using it daily for hours hurts your phone battery, heats up the device, and burns through data fast.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Ignoring router placement.&lt;/strong&gt;&lt;br&gt;
A router stuffed inside a closet behind a TV will give weak signals. Place it in an open area, ideally in the center of your home or workspace.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Not securing the home WiFi.&lt;/strong&gt;&lt;br&gt;
Leaving your home network with the default password is a small but real security risk. Change it once, and forget about it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Blaming the internet for everything.&lt;/strong&gt;&lt;br&gt;
Sometimes it's not WiFi or cellular at fault. It's the website, the server, or that one Chrome tab eating all your RAM. 👀&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;WiFi and cellular data aren't enemies. They're teammates. WiFi is your reliable home base, great for heavy work, study, and long sessions. Cellular data is your portable backup, ready whenever you step outside.&lt;/p&gt;

&lt;p&gt;For most developers, students, and everyday users, &lt;strong&gt;WiFi handles 80% of daily internet needs more cheaply and comfortably&lt;/strong&gt;, while cellular data steps in for the remaining 20% on the go.&lt;/p&gt;

&lt;p&gt;The smartest move isn't picking one. It's knowing &lt;strong&gt;when to use which&lt;/strong&gt;. Once you understand that, you stop wasting money, save battery, and avoid those frustrating "buffering" moments during important calls.&lt;/p&gt;

&lt;p&gt;If this article helped clear things up, share it with a friend who keeps blowing through their data plan. 🚀&lt;/p&gt;

&lt;p&gt;For more easy-to-follow tech blogs, visit &lt;strong&gt;&lt;a href="https://hamidrazadev.com" rel="noopener noreferrer"&gt;hamidrazadev.com&lt;/a&gt;&lt;/strong&gt;, drop a comment if you have a tip I missed, and let me know your own WiFi-vs-data story. I'd genuinely love to read it. 😊&lt;/p&gt;

&lt;p&gt;Happy coding, and may your connection always be stable.&lt;/p&gt;

</description>
      <category>networking</category>
      <category>discuss</category>
      <category>security</category>
      <category>architecture</category>
    </item>
    <item>
      <title>How Web Browsers Work — The Phenomenon Behind Every Web Experience</title>
      <dc:creator>Muhammad Hamid Raza</dc:creator>
      <pubDate>Sun, 03 May 2026 11:27:31 +0000</pubDate>
      <link>https://dev.to/hamidrazadev/how-web-browsers-work-the-phenomenon-behind-every-web-experience-56b9</link>
      <guid>https://dev.to/hamidrazadev/how-web-browsers-work-the-phenomenon-behind-every-web-experience-56b9</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Every time you type a URL and hit Enter, a small miracle unfolds in milliseconds. Most people never think twice about it. Developers should.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  1. Introduction — More Than a Window
&lt;/h2&gt;

&lt;p&gt;Open Chrome. Type a URL. Press Enter. A page appears.&lt;/p&gt;

&lt;p&gt;Simple, right?&lt;/p&gt;

&lt;p&gt;Not even close.&lt;/p&gt;

&lt;p&gt;Behind that instant result is one of the most complex pieces of software ever written. A modern web browser is simultaneously a &lt;strong&gt;network client&lt;/strong&gt;, a &lt;strong&gt;rendering engine&lt;/strong&gt;, a &lt;strong&gt;JavaScript runtime&lt;/strong&gt;, a &lt;strong&gt;security sandbox&lt;/strong&gt;, and a &lt;strong&gt;mini operating system&lt;/strong&gt; — all working in perfect coordination, every single time you browse.&lt;/p&gt;

&lt;p&gt;Google Chrome has over &lt;strong&gt;35 million lines of code&lt;/strong&gt;. Firefox has been actively developed for more than two decades. These aren't simple apps — they're engineering marvels disguised as everyday tools.&lt;/p&gt;

&lt;p&gt;In this post, we're going to pull back the curtain completely. From the moment you hit Enter to the pixel appearing on your screen — this is how browsers &lt;em&gt;actually&lt;/em&gt; work.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Step One — Finding the Server (DNS Resolution)
&lt;/h2&gt;

&lt;p&gt;Before anything loads, the browser needs to answer one question: &lt;em&gt;Where is this website?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Computers don't understand domain names like &lt;code&gt;hamidrazadev.com&lt;/code&gt;. They speak in &lt;strong&gt;IP addresses&lt;/strong&gt; like &lt;code&gt;104.21.45.78&lt;/code&gt;. The system that translates between the two is called &lt;strong&gt;DNS — Domain Name System&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Here's the lookup chain:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Browser Cache&lt;/strong&gt; — Has it visited this domain recently? If yes, use the saved IP.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OS Cache&lt;/strong&gt; — Ask the operating system's own DNS cache.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Router Cache&lt;/strong&gt; — Ask the local network router.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ISP DNS Resolver&lt;/strong&gt; — Ask your internet provider's DNS server.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Root → TLD → Authoritative Nameserver&lt;/strong&gt; — A recursive query through the global DNS hierarchy until the correct IP is returned.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This entire process often completes in &lt;strong&gt;under 20 milliseconds&lt;/strong&gt; — but it's the invisible foundation of every page load.&lt;/p&gt;

&lt;h3&gt;
  
  
  Connecting to the Server — TCP Handshake
&lt;/h3&gt;

&lt;p&gt;With the IP address in hand, the browser opens a &lt;strong&gt;TCP connection&lt;/strong&gt; using a three-way handshake:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Client  →  SYN         →  Server   (I want to connect)
Client  ←  SYN-ACK     ←  Server   (Acknowledged, go ahead)
Client  →  ACK         →  Server   (Connection established)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For &lt;code&gt;https://&lt;/code&gt; sites (which is basically everything today), a &lt;strong&gt;TLS handshake&lt;/strong&gt; follows immediately after — exchanging cryptographic certificates, verifying the server's identity, and establishing an encrypted channel. This is what puts the padlock in your address bar.&lt;/p&gt;

&lt;p&gt;Only &lt;em&gt;after&lt;/em&gt; all of this does the browser send the actual request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="nf"&gt;GET&lt;/span&gt; &lt;span class="nn"&gt;/&lt;/span&gt; &lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt;
&lt;span class="na"&gt;Host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hamidrazadev.com&lt;/span&gt;
&lt;span class="na"&gt;Accept&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;text/html,application/xhtml+xml&lt;/span&gt;
&lt;span class="na"&gt;Accept-Encoding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gzip, deflate, br&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  3. Step Two — The Server Responds
&lt;/h2&gt;

&lt;p&gt;The server processes the request and sends back an &lt;strong&gt;HTTP response&lt;/strong&gt;. This includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Status Code&lt;/strong&gt; — &lt;code&gt;200 OK&lt;/code&gt;, &lt;code&gt;301 Redirect&lt;/code&gt;, &lt;code&gt;404 Not Found&lt;/code&gt;, &lt;code&gt;500 Server Error&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Response Headers&lt;/strong&gt; — Content type, caching rules, security policies, cookies&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Response Body&lt;/strong&gt; — The actual HTML markup&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One of the most important things to understand here: &lt;strong&gt;the browser does not wait for the full HTML to download before it starts working.&lt;/strong&gt; It reads the response as a &lt;strong&gt;stream&lt;/strong&gt;, processing bytes as they arrive over the network. This is called &lt;strong&gt;streaming parsing&lt;/strong&gt; — and it's the reason you sometimes see a page begin rendering before it's fully loaded.&lt;/p&gt;

&lt;p&gt;Modern browsers also take advantage of &lt;strong&gt;HTTP/2&lt;/strong&gt; and &lt;strong&gt;HTTP/3&lt;/strong&gt;, which allow multiple resources (HTML, CSS, JS, images) to be fetched over a &lt;em&gt;single&lt;/em&gt; connection simultaneously — a massive leap over HTTP/1.1's one-request-at-a-time model.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Step Three — Parsing HTML into the DOM
&lt;/h2&gt;

&lt;p&gt;As HTML bytes arrive, the browser's &lt;strong&gt;HTML Parser&lt;/strong&gt; gets to work. Its job is to convert raw markup text into a structured, in-memory data structure called the &lt;strong&gt;DOM — Document Object Model&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Think of it as a tree:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Document
└── &amp;lt;html&amp;gt;
    ├── &amp;lt;head&amp;gt;
    │   ├── &amp;lt;title&amp;gt;My Site&amp;lt;/title&amp;gt;
    │   └── &amp;lt;link rel="stylesheet" href="styles.css"&amp;gt;
    └── &amp;lt;body&amp;gt;
        ├── &amp;lt;header&amp;gt;
        │   └── &amp;lt;nav&amp;gt;...&amp;lt;/nav&amp;gt;
        ├── &amp;lt;main&amp;gt;
        │   └── &amp;lt;article&amp;gt;...&amp;lt;/article&amp;gt;
        └── &amp;lt;footer&amp;gt;...&amp;lt;/footer&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every HTML element becomes a &lt;strong&gt;node&lt;/strong&gt;. Every node has a parent, zero or more children, and sibling relationships. This tree is what JavaScript manipulates at runtime — adding, removing, and modifying nodes to create dynamic UIs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Parser Blocking — The Hidden Performance Trap
&lt;/h3&gt;

&lt;p&gt;Parsing is not always a straight line. The HTML parser can get &lt;em&gt;blocked&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;&amp;lt;link rel="stylesheet"&amp;gt;&lt;/code&gt;&lt;/strong&gt; — Triggers a CSS file fetch. Rendering is blocked until CSS is downloaded and parsed (to avoid a flash of unstyled content).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt;&lt;/strong&gt; (without &lt;code&gt;async&lt;/code&gt;/&lt;code&gt;defer&lt;/code&gt;) — The parser &lt;em&gt;stops completely&lt;/em&gt; to download and execute the JavaScript before continuing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;video&amp;gt;&lt;/code&gt;&lt;/strong&gt; — Non-blocking; parallel fetches are fired off but don't halt the parser.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is exactly why developers are told to put &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tags at the bottom of the body, or use &lt;code&gt;defer&lt;/code&gt; — to avoid stalling the parser mid-document.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Step Four — Building the CSSOM
&lt;/h2&gt;

&lt;p&gt;While the HTML parser builds the DOM, a parallel process handles your CSS — constructing the &lt;strong&gt;CSSOM (CSS Object Model)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Every style rule, from every source (&lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt; tags, external stylesheets, inline styles) is parsed and organized into its own tree. The browser then applies the &lt;strong&gt;cascade algorithm&lt;/strong&gt; to determine which styles actually apply to each element, resolving conflicts using:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Origin&lt;/strong&gt; — Browser defaults vs. developer styles vs. user overrides&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Specificity&lt;/strong&gt; — &lt;code&gt;#id&lt;/code&gt; &amp;gt; &lt;code&gt;.class&lt;/code&gt; &amp;gt; &lt;code&gt;element&lt;/code&gt; selector&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Order of appearance&lt;/strong&gt; — Later rules override earlier ones at equal specificity&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inheritance&lt;/strong&gt; — Some properties (like &lt;code&gt;font-family&lt;/code&gt;) inherit from parent to child automatically&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Once both the DOM and CSSOM are complete, the browser merges them into the &lt;strong&gt;Render Tree&lt;/strong&gt; — a new tree containing &lt;em&gt;only&lt;/em&gt; the visible elements, each annotated with their final computed styles.&lt;/p&gt;

&lt;p&gt;Elements with &lt;code&gt;display: none&lt;/code&gt; are excluded entirely. Elements with &lt;code&gt;visibility: hidden&lt;/code&gt; remain in the tree (they still occupy space) but are painted transparently.&lt;/p&gt;




&lt;h2&gt;
  
  
  6. Step Five — The Rendering Pipeline
&lt;/h2&gt;

&lt;p&gt;With the render tree ready, the browser enters the &lt;strong&gt;rendering pipeline&lt;/strong&gt; — the process of turning data into actual pixels. This happens in four distinct stages:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Layout (Reflow)
&lt;/h3&gt;

&lt;p&gt;The browser calculates the &lt;strong&gt;exact position and dimensions&lt;/strong&gt; of every element on the page. This involves:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Box model calculations (margin, border, padding, content width/height)&lt;/li&gt;
&lt;li&gt;Flexbox and CSS Grid algorithms&lt;/li&gt;
&lt;li&gt;Text wrapping and line-breaking&lt;/li&gt;
&lt;li&gt;Relative and absolute positioning&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Layout is computed from the root of the render tree downward. Changing a single element's size can &lt;strong&gt;trigger a reflow&lt;/strong&gt; of its descendants and siblings — which is why layout-thrashing in JavaScript is a serious performance concern.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Paint
&lt;/h3&gt;

&lt;p&gt;The browser walks the render tree and records &lt;strong&gt;paint operations&lt;/strong&gt; — drawing text, colors, borders, box shadows, images — layer by layer. This stage produces a list of draw calls, not actual pixels yet.&lt;/p&gt;

&lt;p&gt;Modern browsers split the page into multiple &lt;strong&gt;layers&lt;/strong&gt; (think: transparent sheets stacked together). Elements that animate or change frequently are promoted to their own layer so they can be updated independently without repainting the rest of the page.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Rasterization
&lt;/h3&gt;

&lt;p&gt;Paint commands are converted to actual &lt;strong&gt;pixels&lt;/strong&gt; — either on the CPU or, more commonly, the GPU. The page is broken into &lt;strong&gt;tiles&lt;/strong&gt; and rasterized in parallel for speed.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Composite
&lt;/h3&gt;

&lt;p&gt;The GPU combines all rasterized layers into the &lt;strong&gt;final frame&lt;/strong&gt; displayed on screen. CSS properties like &lt;code&gt;transform&lt;/code&gt; and &lt;code&gt;opacity&lt;/code&gt; are handled entirely at this stage — which is why they're the gold standard for performant animations. They skip Layout and Paint entirely.&lt;/p&gt;

&lt;p&gt;The full pipeline looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;JavaScript → Style Recalc → Layout → Paint → Composite
     ↑                                              ↓
  DOM/CSSOM Changes                         Frame on Screen
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Browsers target &lt;strong&gt;60 frames per second&lt;/strong&gt; — that's one frame every &lt;strong&gt;16.67ms&lt;/strong&gt;. Miss that budget, and you get visible jank.&lt;/p&gt;




&lt;h2&gt;
  
  
  7. Step Six — JavaScript Execution
&lt;/h2&gt;

&lt;p&gt;No browser discussion is complete without the &lt;strong&gt;JavaScript engine&lt;/strong&gt; — arguably the most complex component of all.&lt;/p&gt;

&lt;p&gt;Different browsers ship different engines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;V8&lt;/strong&gt; — Chrome, Edge, Node.js&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SpiderMonkey&lt;/strong&gt; — Firefox&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JavaScriptCore (Nitro)&lt;/strong&gt; — Safari&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They all follow a similar pipeline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Source Code → AST → Bytecode → JIT Machine Code
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Parsing&lt;/strong&gt; — JS source is parsed into an &lt;strong&gt;Abstract Syntax Tree (AST)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bytecode Compilation&lt;/strong&gt; — The AST is compiled to bytecode by an interpreter (e.g., V8's &lt;em&gt;Ignition&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JIT Optimization&lt;/strong&gt; — Frequently-executed ("hot") code paths are recompiled to highly optimized native machine code (e.g., V8's &lt;em&gt;TurboFan&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deoptimization&lt;/strong&gt; — If assumptions change (e.g., a variable's type changes), the JIT compiler throws away optimized code and falls back to bytecode&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Garbage Collection&lt;/strong&gt; — Unreachable memory is automatically freed using a generational GC algorithm&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  The Event Loop — Why JS Doesn't Freeze
&lt;/h3&gt;

&lt;p&gt;JavaScript is &lt;strong&gt;single-threaded&lt;/strong&gt; — one call stack, one execution context at a time. Yet it handles async operations (network requests, timers, events) without blocking. How?&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Event Loop&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Call Stack → empty? → Check Microtask Queue → Check Macrotask Queue → Push callback → Repeat
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Long-running browser operations (fetch, setTimeout, DOM events) are handled by &lt;strong&gt;Web APIs&lt;/strong&gt; in C++ — outside the JS thread.&lt;/li&gt;
&lt;li&gt;When they complete, their callbacks enter a &lt;strong&gt;queue&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The event loop picks callbacks off the queue and pushes them onto the call stack &lt;em&gt;only when it's empty&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is why &lt;code&gt;async/await&lt;/code&gt; and Promises don't block the UI — they defer callbacks until the call stack is free.&lt;/p&gt;




&lt;h2&gt;
  
  
  8. The Bigger Picture — Security, Caching &amp;amp; Performance
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Process Isolation &amp;amp; The Sandbox
&lt;/h3&gt;

&lt;p&gt;Modern browsers run each tab in its own &lt;strong&gt;sandboxed OS process&lt;/strong&gt;. Even if malicious JavaScript runs in one tab, it cannot access:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Another tab's DOM or data&lt;/li&gt;
&lt;li&gt;Your file system&lt;/li&gt;
&lt;li&gt;OS-level resources&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is enforced at the OS level — not just by browser rules. A crashed tab crashes its process, not the entire browser.&lt;/p&gt;

&lt;p&gt;Key security mechanisms include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Same-Origin Policy (SOP)&lt;/strong&gt; — JavaScript on &lt;code&gt;site-a.com&lt;/code&gt; cannot read data from &lt;code&gt;site-b.com&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Content Security Policy (CSP)&lt;/strong&gt; — Server-defined rules about which scripts and resources are allowed to load&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HTTPS + HSTS&lt;/strong&gt; — Enforces encrypted connections and prevents downgrade attacks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-Origin Resource Sharing (CORS)&lt;/strong&gt; — Controlled exceptions to SOP for trusted cross-origin requests&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Caching — Speed Through Memory
&lt;/h3&gt;

&lt;p&gt;Browsers cache aggressively to eliminate redundant work:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Cache Type&lt;/th&gt;
&lt;th&gt;Lifetime&lt;/th&gt;
&lt;th&gt;Speed&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Memory Cache&lt;/td&gt;
&lt;td&gt;Tab session&lt;/td&gt;
&lt;td&gt;Instant&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Disk Cache&lt;/td&gt;
&lt;td&gt;Controlled by HTTP headers&lt;/td&gt;
&lt;td&gt;Fast&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Service Worker Cache&lt;/td&gt;
&lt;td&gt;Programmatic / Persistent&lt;/td&gt;
&lt;td&gt;Flexible&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;Cache-Control&lt;/code&gt;, &lt;code&gt;ETag&lt;/code&gt;, and &lt;code&gt;Last-Modified&lt;/code&gt; headers give servers fine-grained control over how long resources are cached and when they expire.&lt;/p&gt;

&lt;h3&gt;
  
  
  Modern Performance Techniques
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;&amp;lt;link rel="preload"&amp;gt;&lt;/code&gt;&lt;/strong&gt; — Fetch critical resources (fonts, hero images) before the parser discovers them&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;&amp;lt;link rel="dns-prefetch"&amp;gt;&lt;/code&gt;&lt;/strong&gt; — Resolve third-party domains early&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;loading="lazy"&lt;/code&gt;&lt;/strong&gt; — Defer off-screen image/iframe loads&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;async&lt;/code&gt; / &lt;code&gt;defer&lt;/code&gt;&lt;/strong&gt; on scripts — Avoid parser blocking&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HTTP/3 + QUIC&lt;/strong&gt; — Faster connection establishment, especially on lossy mobile networks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Brotli Compression&lt;/strong&gt; — Smaller transfer sizes than gzip for text-based assets&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Final Thoughts — Know Your Runtime
&lt;/h2&gt;

&lt;p&gt;Every page load you've ever experienced — every click, every scroll, every animation — was the product of this entire pipeline running in perfect orchestration, usually in under a second.&lt;/p&gt;

&lt;p&gt;As a developer, understanding this isn't just trivia. It's &lt;strong&gt;leverage&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It's the difference between a 4-second load and a 0.9-second one. Between janky scroll and buttery 60fps. Between an XSS vulnerability and a hardened app. Between a developer who writes code and one who understands the &lt;em&gt;system&lt;/em&gt; their code runs in.&lt;/p&gt;

&lt;p&gt;The browser is your runtime. Respect it. Understand it. And build for it with intention.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>browser</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Run Powerful AI Models Offline on Your Phone with Google AI Edge Gallery (Android &amp; iOS)</title>
      <dc:creator>Muhammad Hamid Raza</dc:creator>
      <pubDate>Fri, 01 May 2026 10:24:13 +0000</pubDate>
      <link>https://dev.to/hamidrazadev/run-powerful-ai-models-offline-on-your-phone-with-google-ai-edge-gallery-android-ios-p3d</link>
      <guid>https://dev.to/hamidrazadev/run-powerful-ai-models-offline-on-your-phone-with-google-ai-edge-gallery-android-ios-p3d</guid>
      <description>&lt;p&gt;Have you ever wished you could use a powerful AI assistant without burning through your mobile data — or worrying about your private conversations being sent to some server halfway around the world?&lt;/p&gt;

&lt;p&gt;That wish just became reality. 🚀&lt;/p&gt;

&lt;p&gt;Google's &lt;strong&gt;AI Edge Gallery&lt;/strong&gt; app lets you download and run real open-source large language models (LLMs) directly on your iPhone or Android phone. No internet. No cloud. No data leaving your device. Just raw AI power running straight from your hardware.&lt;/p&gt;

&lt;p&gt;But wait — how good can phone AI actually be? Better than you'd expect. Let's dig in.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Is Google AI Edge Gallery?
&lt;/h2&gt;

&lt;p&gt;AI Edge Gallery is a free, open-source app built by Google's Research team — available on both &lt;strong&gt;Android&lt;/strong&gt; and &lt;strong&gt;iPhone&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Instead of sending your questions to a remote server like most AI apps do, it downloads AI models directly onto your device and runs them locally using your phone's CPU and GPU.&lt;/p&gt;

&lt;p&gt;Think of it as a mini AI computer in your pocket — one that works even in airplane mode.&lt;/p&gt;

&lt;p&gt;The app supports multiple open-source models, including Google's own &lt;strong&gt;Gemma 4&lt;/strong&gt; family, and gives you tools for chatting, image analysis, voice transcription, and even simple device automation — all completely offline.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Actually Matters
&lt;/h2&gt;

&lt;p&gt;Most AI tools today are cloud-dependent. That means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your prompts travel to remote servers&lt;/li&gt;
&lt;li&gt;You need a stable internet connection&lt;/li&gt;
&lt;li&gt;Slow networks mean slow responses&lt;/li&gt;
&lt;li&gt;You have zero control over what happens to your data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AI Edge Gallery flips all of that. Everything runs &lt;strong&gt;on-device&lt;/strong&gt;, which means your data never leaves your phone. For developers, students, journalists, or anyone handling sensitive information, that's a big deal.&lt;/p&gt;

&lt;p&gt;There's also the offline angle. If you're traveling, in a low-connectivity area, or just don't want to burn through your data plan, local AI is incredibly useful.&lt;/p&gt;




&lt;h2&gt;
  
  
  How to Download It
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;For Android:&lt;/strong&gt;&lt;br&gt;
Search for &lt;strong&gt;"AI Edge Gallery"&lt;/strong&gt; on the Google Play Store (by Research at Google). Requires Android 12 or higher. App size: ~23 MB.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For iPhone:&lt;/strong&gt;&lt;br&gt;
Search for &lt;strong&gt;"Google AI Edge Gallery"&lt;/strong&gt; on the Apple App Store, or visit:&lt;br&gt;
&lt;a href="https://apps.apple.com/us/app/google-ai-edge-gallery/id6749645337" rel="noopener noreferrer"&gt;apps.apple.com/us/app/google-ai-edge-gallery/id6749645337&lt;/a&gt;&lt;br&gt;
App size: ~68 MB. Requires iOS 13+. Rated 4.0 stars with 1,000+ ratings.&lt;/p&gt;




&lt;h2&gt;
  
  
  Key Features Worth Knowing 💡
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🗨️ AI Chat with Thinking Mode
&lt;/h3&gt;

&lt;p&gt;Have multi-turn conversations with the model just like any AI chat app. The really interesting part? You can toggle &lt;strong&gt;Thinking Mode&lt;/strong&gt; to see the model's step-by-step reasoning before it gives you an answer. It's like watching the AI think out loud — incredibly useful for learning or understanding complex responses.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Thinking Mode currently works with supported models, starting with the Gemma 4 family.)&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  🖼️ Ask Image (Multimodal AI)
&lt;/h3&gt;

&lt;p&gt;Point your camera at something — a math problem on a whiteboard, a plant in your garden, a broken error message on your screen — and ask the AI about it. It uses your device's camera or photo gallery to give you visual, detailed answers.&lt;/p&gt;

&lt;h3&gt;
  
  
  🎙️ Audio Scribe
&lt;/h3&gt;

&lt;p&gt;Speak into your phone and the app transcribes your voice to text in real time. It handles translation too. All of it happens on-device with no audio ever being sent to a server.&lt;/p&gt;

&lt;h3&gt;
  
  
  🧪 Prompt Lab
&lt;/h3&gt;

&lt;p&gt;This is the developer's favorite corner of the app. You get a dedicated workspace to test prompts with full control over model parameters like &lt;strong&gt;temperature&lt;/strong&gt; and &lt;strong&gt;top-k&lt;/strong&gt;. Perfect for experimenting, learning, and fine-tuning your prompting skills.&lt;/p&gt;

&lt;h3&gt;
  
  
  🤖 Agent Skills
&lt;/h3&gt;

&lt;p&gt;This takes the app beyond simple chatting. You can add tools like Wikipedia lookups, interactive maps, and rich visual summary cards to make the AI more capable and grounded. You can even load custom skills from a URL or browse community contributions on GitHub.&lt;/p&gt;

&lt;h3&gt;
  
  
  📱 Mobile Actions
&lt;/h3&gt;

&lt;p&gt;On both platforms, the app can control certain device functions and automate simple tasks — powered by a lightweight fine-tuned model called FunctionGemma 270m, running entirely offline. On iOS, features like controlling the flashlight work well, though more advanced actions like creating calendar events are still limited.&lt;/p&gt;

&lt;h3&gt;
  
  
  🌱 Tiny Garden
&lt;/h3&gt;

&lt;p&gt;A fun little bonus — a mini-game where you use natural language to plant and harvest a virtual garden. It's experimental and powered by FunctionGemma 270m. Quirky, but genuinely impressive as a demo of what small models can do.&lt;/p&gt;

&lt;h3&gt;
  
  
  📊 Model Management &amp;amp; Benchmarking
&lt;/h3&gt;

&lt;p&gt;Download models from a curated list or load your own custom models. Run benchmark tests to see exactly how fast each model runs on &lt;strong&gt;your specific hardware&lt;/strong&gt;. Results vary a lot between devices, so this is worth doing before you dive in.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step-by-Step: Getting Started
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1 — Install the App
&lt;/h3&gt;

&lt;p&gt;Download from the &lt;strong&gt;Google Play Store&lt;/strong&gt; (Android) or the &lt;strong&gt;Apple App Store&lt;/strong&gt; (iPhone) and open it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2 — Download a Model
&lt;/h3&gt;

&lt;p&gt;You'll see a list of available models. Tap one and download it. The models are larger files — usually several hundred MB to a few GB — so &lt;strong&gt;download on Wi-Fi&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The home screen features the Gemma 4 family prominently. &lt;strong&gt;Start with a smaller variant&lt;/strong&gt; (like Gemma 4 2B) if you have a mid-range device with limited RAM.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3 — Pick a Feature
&lt;/h3&gt;

&lt;p&gt;Once your model is downloaded, choose what you want to do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AI Chat&lt;/strong&gt; for conversation and multi-turn dialogue&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prompt Lab&lt;/strong&gt; for controlled testing and experimentation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ask Image&lt;/strong&gt; for visual queries using your camera&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Audio Scribe&lt;/strong&gt; for voice-to-text transcription&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agent Skills&lt;/strong&gt; for tool-augmented AI responses&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 4 — Enable Thinking Mode (Optional but Fascinating)
&lt;/h3&gt;

&lt;p&gt;In the AI Chat screen with a Gemma 4 model loaded, tap the &lt;strong&gt;Thinking Mode&lt;/strong&gt; toggle. Ask a complex question — like "How many R's are in strawberry?" — and watch the model break down its reasoning step by step before answering.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5 — Run a Benchmark
&lt;/h3&gt;

&lt;p&gt;Head to &lt;strong&gt;Model Management&lt;/strong&gt; and run a benchmark test. You'll get real performance numbers for your device. It takes under a minute and helps you understand your hardware's actual capabilities before downloading heavier models.&lt;/p&gt;




&lt;h2&gt;
  
  
  On-Device AI vs Cloud AI: Quick Comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;On-Device (AI Edge Gallery)&lt;/th&gt;
&lt;th&gt;Cloud AI (ChatGPT, Gemini Web, etc.)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Internet required&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;td&gt;✅ Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Data privacy&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ Fully local&lt;/td&gt;
&lt;td&gt;⚠️ Sent to servers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Speed&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Depends on hardware&lt;/td&gt;
&lt;td&gt;Depends on connection&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Model size&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Limited by device RAM&lt;/td&gt;
&lt;td&gt;Very large models&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cost&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;Often subscription-based&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Latest models&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Open-source only&lt;/td&gt;
&lt;td&gt;Proprietary + cutting-edge&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Custom model support&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ Load your own&lt;/td&gt;
&lt;td&gt;❌ Limited&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Works offline&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ Always&lt;/td&gt;
&lt;td&gt;❌ Never&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;The honest take:&lt;/strong&gt; Cloud AI models like GPT-4o or Gemini 1.5 Pro are still more capable for complex tasks. On-device AI is the best choice for privacy-sensitive use cases, offline situations, learning about AI behavior, and low or no connectivity scenarios.&lt;/p&gt;




&lt;h2&gt;
  
  
  Tips for the Best Experience 🔧
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;✅ Do this:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Download models over Wi-Fi — they're large files&lt;/li&gt;
&lt;li&gt;Start with smaller models (2B–3B parameters) on mid-range phones&lt;/li&gt;
&lt;li&gt;Use Prompt Lab to understand how temperature and top-k affect model output&lt;/li&gt;
&lt;li&gt;Try Agent Skills to add Wikipedia, maps, and visual tools to your AI&lt;/li&gt;
&lt;li&gt;Run a benchmark first before downloading heavier models&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;❌ Avoid this:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Don't expect cloud-level accuracy from a model running on phone hardware&lt;/li&gt;
&lt;li&gt;Don't run very large models on devices with under 6GB RAM — they'll struggle&lt;/li&gt;
&lt;li&gt;Don't skip the benchmark — it gives you genuinely useful data about your device&lt;/li&gt;
&lt;li&gt;Don't give up after one slow response — performance improves once the model is fully loaded into memory&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Common Mistakes People Make
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Downloading the biggest model first
&lt;/h3&gt;

&lt;p&gt;Bigger parameters doesn't always mean better performance on your device. A very large model might run slowly or even crash on phones with limited RAM. &lt;strong&gt;Start small, benchmark, then scale up.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Expecting the same output quality as GPT-4 or Gemini Ultra
&lt;/h3&gt;

&lt;p&gt;On-device models are improving rapidly, but they're optimized for size and speed, not maximum intelligence. Go in expecting a capable, private, offline assistant — and you'll genuinely be impressed. Go in expecting a match for the largest cloud models — and you'll be let down.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ignoring which models are optimized for your chip
&lt;/h3&gt;

&lt;p&gt;Android users on Qualcomm Snapdragon devices now have &lt;strong&gt;Gemma 3 1B NPU support&lt;/strong&gt;, meaning the model runs on the neural processing unit for much faster inference. Always check model details before downloading to pick the best-optimized version for your hardware.&lt;/p&gt;

&lt;h3&gt;
  
  
  Not trying Agent Skills
&lt;/h3&gt;

&lt;p&gt;Many users stick to basic chat and miss the real power of the app. Agent Skills — Wikipedia grounding, interactive maps, visual summaries — make the AI dramatically more useful. Spend five minutes here and you'll see the difference.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Google AI Edge Gallery is one of the most exciting things happening in mobile AI right now. It brings real, powerful open-source models to your Android or iPhone — offline, private, and completely free.&lt;/p&gt;

&lt;p&gt;Is it going to replace your cloud AI subscription tomorrow? Probably not for complex tasks. But as a &lt;strong&gt;developer tool, a privacy-focused assistant, a learning sandbox, and a reliable offline companion&lt;/strong&gt;, it's genuinely impressive and improving with every update.&lt;/p&gt;

&lt;p&gt;The open-source, community-driven nature makes it even more interesting. Developers are already building and sharing custom Agent Skills, contributing models, and constantly pushing what a phone can do.&lt;/p&gt;

&lt;p&gt;Download it, try a small Gemma 4 model, toggle Thinking Mode, and see what your phone is actually capable of. You might be surprised. 😊&lt;/p&gt;

&lt;p&gt;For more dev tools, AI guides, and practical developer content, visit &lt;strong&gt;&lt;a href="https://hamidrazadev.com" rel="noopener noreferrer"&gt;hamidrazadev.com&lt;/a&gt;&lt;/strong&gt;. If this post was helpful, share it with a developer or tech friend who'd appreciate it!&lt;/p&gt;

</description>
      <category>android</category>
      <category>ios</category>
      <category>ai</category>
      <category>opensource</category>
    </item>
    <item>
      <title>10 Tips to Use Claude for Best Performance (Stop Wasting Tokens)</title>
      <dc:creator>Muhammad Hamid Raza</dc:creator>
      <pubDate>Thu, 30 Apr 2026 10:51:22 +0000</pubDate>
      <link>https://dev.to/hamidrazadev/10-tips-to-use-claude-for-best-performance-stop-wasting-tokens-57f1</link>
      <guid>https://dev.to/hamidrazadev/10-tips-to-use-claude-for-best-performance-stop-wasting-tokens-57f1</guid>
      <description>&lt;p&gt;You open Claude, type a quick message, get a mediocre response, tweak it, re-send it, get a slightly better one, tweak it again… and suddenly you have burned through half your daily message limit trying to get one decent paragraph.&lt;/p&gt;

&lt;p&gt;Sound familiar? 😅&lt;/p&gt;

&lt;p&gt;Most people treat Claude like a search engine — type something vague, hope for the best, then complain when the output misses the mark. But Claude is not a search engine. It is a reasoning model. And the better your input, the better your output. Every time.&lt;/p&gt;

&lt;p&gt;So the real question is: &lt;strong&gt;are you getting the most out of every single prompt, or are you silently wasting tokens on back-and-forth you could have avoided?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here are 10 practical tips that will help you get sharp, accurate, useful results from Claude — without burning through your token budget for nothing.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Are Tokens, and Why Should You Care?
&lt;/h2&gt;

&lt;p&gt;Before we dive into the tips, let us get one thing straight.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;token&lt;/strong&gt; is roughly a word or part of a word. When you send a message to Claude — and when Claude responds — both sides use tokens. If you are on a usage-limited plan, tokens are essentially your budget. Waste them on unclear prompts and long back-and-forths, and you hit your limit faster without getting the quality you needed.&lt;/p&gt;

&lt;p&gt;Even if tokens are not a concern for you right now, efficient prompting saves time, reduces confusion, and gets you better results. That is always worth it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Prompting Style Actually Matters
&lt;/h2&gt;

&lt;p&gt;Claude is powerful, but it is not a mind reader.&lt;/p&gt;

&lt;p&gt;It works best when you give it clear context, clear instructions, and a clear goal. When you leave those things out, Claude has to guess — and even a well-trained AI guessing about your intent is still just guessing.&lt;/p&gt;

&lt;p&gt;Better prompts mean fewer re-tries. Fewer re-tries mean fewer tokens spent. And better responses mean less frustration. It is a win on every side.&lt;/p&gt;




&lt;h2&gt;
  
  
  10 Tips to Get the Best Performance from Claude
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. 🎯 Be Specific About What You Want
&lt;/h3&gt;

&lt;p&gt;Vague prompts produce vague answers. If you type &lt;em&gt;"explain JavaScript"&lt;/em&gt;, you could get anything from a 500-word intro to a full history of the language.&lt;/p&gt;

&lt;p&gt;Instead, say: &lt;em&gt;"Explain JavaScript closures in simple terms with one short example. Keep it under 200 words."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Specificity is your best friend. Tell Claude what topic, what depth, what format, and what length. That one habit alone will improve your results dramatically.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. 🧑‍💼 Give Claude a Role
&lt;/h3&gt;

&lt;p&gt;Claude performs better when it knows what persona to take on.&lt;/p&gt;

&lt;p&gt;Start your prompt with something like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;"You are a senior React developer..."&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;"You are a friendly teacher explaining this to a 12-year-old..."&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;"You are a technical writer creating documentation..."&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This small change shapes the tone, depth, and style of the entire response. It saves you multiple follow-up messages trying to adjust the voice.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. 📋 Provide Context Upfront
&lt;/h3&gt;

&lt;p&gt;Claude has no memory of what you did in a previous conversation unless you tell it. Jumping straight into a complex question without context forces Claude to make assumptions — and assumptions lead to mismatched answers.&lt;/p&gt;

&lt;p&gt;Before asking your main question, give Claude the background it needs:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"I am building a Next.js app with TypeScript. I am using Supabase for authentication. I have this error in my sign-in function: [paste error]. What could be causing it?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A bit more setup upfront = a much more useful answer on the first try.&lt;/p&gt;




&lt;h3&gt;
  
  
  4. ✂️ Use Clear, Short Sentences
&lt;/h3&gt;

&lt;p&gt;Long, winding prompts confuse priorities. When a prompt has ten different ideas crammed into one paragraph, Claude has to figure out what you actually want most — and it might pick the wrong priority.&lt;/p&gt;

&lt;p&gt;Keep your prompts clean and structured. Break big requests into clear points if needed. Short sentences are easier to follow for both humans and AI.&lt;/p&gt;




&lt;h3&gt;
  
  
  5. 📐 Specify the Format You Need
&lt;/h3&gt;

&lt;p&gt;Do you want bullet points? A numbered list? A code block? A paragraph? A table?&lt;/p&gt;

&lt;p&gt;Claude will pick a default format if you do not say anything. Sometimes that works. Sometimes it does not. Rather than sending a follow-up message asking for a reformat, just include it in your original prompt:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Give me the answer as a numbered list."&lt;/em&gt;&lt;br&gt;
&lt;em&gt;"Respond only in a code block with comments."&lt;/em&gt;&lt;br&gt;
&lt;em&gt;"Write this as a short paragraph, not bullet points."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;One sentence of format instruction can save you two or three re-prompts.&lt;/p&gt;




&lt;h3&gt;
  
  
  6. 🔢 Set a Length Expectation
&lt;/h3&gt;

&lt;p&gt;Claude can write two sentences or two thousand words. Without guidance, it picks somewhere in the middle — which is often not what you needed.&lt;/p&gt;

&lt;p&gt;If you want a quick summary, say &lt;em&gt;"Keep it under 100 words."&lt;/em&gt;&lt;br&gt;
If you want depth, say &lt;em&gt;"Write a detailed explanation with examples."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Controlling length is one of the easiest ways to get cleaner, more useful responses without any wasted words — on either side.&lt;/p&gt;




&lt;h3&gt;
  
  
  7. ⛔ Tell Claude What NOT to Do
&lt;/h3&gt;

&lt;p&gt;This one is underrated.&lt;/p&gt;

&lt;p&gt;Negative instructions are just as useful as positive ones. If you do not want Claude to add a conclusion, say so. If you do not want technical jargon, mention it. If you do not want a list when you specifically need prose, be clear.&lt;/p&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;"Do not add an introduction. Start directly with the steps."&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;"Do not include any code. Just explain the concept in plain English."&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;"Do not suggest alternatives. Just fix what I gave you."&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These small guardrails stop Claude from going in a direction you did not want — which means no wasted tokens correcting it.&lt;/p&gt;




&lt;h3&gt;
  
  
  8. 🔁 Use Follow-Up Prompts Smartly
&lt;/h3&gt;

&lt;p&gt;Even with a great first prompt, sometimes you will want a tweak. That is totally normal. But there is a right way to do follow-ups.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Instead of:&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;"Change it."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Say:&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;"Make the tone more casual and remove the second paragraph."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Vague follow-ups force Claude to guess again. Specific follow-ups land on the first try. The goal is fewer rounds of back-and-forth, not more.&lt;/p&gt;




&lt;h3&gt;
  
  
  9. 🗂️ Break Big Tasks into Smaller Steps
&lt;/h3&gt;

&lt;p&gt;Asking Claude to &lt;em&gt;"build me a full e-commerce website"&lt;/em&gt; in one prompt is a recipe for a bloated, half-right response that you then spend ages correcting.&lt;/p&gt;

&lt;p&gt;For big or complex tasks, break them into steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;em&gt;"First, write the product listing component in React."&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;"Now write the cart logic."&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;"Now connect the cart to the listing component."&lt;/em&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This gives you better control, cleaner output, and easier debugging if something goes wrong. Smaller tasks also use context more efficiently.&lt;/p&gt;




&lt;h3&gt;
  
  
  10. 💾 Reuse Prompts That Work
&lt;/h3&gt;

&lt;p&gt;When you find a prompt structure that consistently gives you great results, save it. Seriously — keep a small notes file or a Notion doc with your best-performing prompts.&lt;/p&gt;

&lt;p&gt;Whether it is a prompt for writing blog outlines, debugging code, summarizing documentation, or generating component ideas — a saved prompt you can reuse is a token-efficient shortcut for every future task.&lt;/p&gt;

&lt;p&gt;Good prompts are assets. Treat them like one.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick Comparison: Weak Prompt vs Strong Prompt
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Weak Prompt&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Strong Prompt&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Topic&lt;/td&gt;
&lt;td&gt;Vague or missing&lt;/td&gt;
&lt;td&gt;Clearly stated&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Context&lt;/td&gt;
&lt;td&gt;None given&lt;/td&gt;
&lt;td&gt;Background provided&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Format&lt;/td&gt;
&lt;td&gt;Not specified&lt;/td&gt;
&lt;td&gt;Requested explicitly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Length&lt;/td&gt;
&lt;td&gt;Not mentioned&lt;/td&gt;
&lt;td&gt;Defined&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Role&lt;/td&gt;
&lt;td&gt;Default&lt;/td&gt;
&lt;td&gt;Assigned persona&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Result&lt;/td&gt;
&lt;td&gt;Hit or miss&lt;/td&gt;
&lt;td&gt;Consistently useful&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The difference between these two columns is not talent. It is just habit.&lt;/p&gt;




&lt;h2&gt;
  
  
  Common Mistakes People Make with Claude
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Treating Claude like Google.&lt;/strong&gt;&lt;br&gt;
Claude is not for searching. It is for reasoning, writing, explaining, and generating. Use it for what it is good at.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Sending one giant wall of text.&lt;/strong&gt;&lt;br&gt;
Unstructured prompts produce unstructured answers. Format your input so Claude can follow it clearly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Not iterating smartly.&lt;/strong&gt;&lt;br&gt;
Sending the exact same prompt again after a bad response will not help. Change something — the format, the framing, the context — and it will respond differently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Assuming Claude remembers previous chats.&lt;/strong&gt;&lt;br&gt;
By default, each conversation starts fresh. If your task depends on past context, include a brief summary at the start.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Asking for everything at once.&lt;/strong&gt;&lt;br&gt;
Big prompts with ten different goals rarely produce ten great outputs. Chunk your work. You will thank yourself later.&lt;/p&gt;




&lt;h2&gt;
  
  
  Best Practices at a Glance ✅
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;✅ Be specific about topic, format, tone, and length&lt;/li&gt;
&lt;li&gt;✅ Assign a role when the task has a clear persona&lt;/li&gt;
&lt;li&gt;✅ Give context before jumping into the question&lt;/li&gt;
&lt;li&gt;✅ Use negative instructions to set boundaries&lt;/li&gt;
&lt;li&gt;✅ Break large tasks into smaller, clean steps&lt;/li&gt;
&lt;li&gt;✅ Save prompt templates that work well for you&lt;/li&gt;
&lt;li&gt;❌ Do not be vague and expect great results&lt;/li&gt;
&lt;li&gt;❌ Do not skip context and hope Claude figures it out&lt;/li&gt;
&lt;li&gt;❌ Do not ask Claude to redo something without telling it what to change&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Claude is a genuinely powerful tool — but only when you give it what it needs to perform. Most people leave a lot of quality on the table simply because of unclear or incomplete prompts.&lt;/p&gt;

&lt;p&gt;You do not need to be a prompt engineering expert. You just need to be clear, specific, and intentional. Follow these 10 tips and you will get faster, sharper, and more accurate responses — with far fewer re-tries.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Less re-prompting. Less wasted tokens. More results.&lt;/strong&gt; That is the goal.&lt;/p&gt;

&lt;p&gt;If this helped you, check out more developer tips and guides on &lt;a href="https://hamidrazadev.com" rel="noopener noreferrer"&gt;hamidrazadev.com&lt;/a&gt; 🚀&lt;/p&gt;

&lt;p&gt;Share this with a fellow developer who is still sending one-liner prompts and wondering why the output is not great. They will appreciate you for it. 😊&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>discuss</category>
      <category>webdev</category>
    </item>
    <item>
      <title>VS Code 1.118 Is Here — And It's All About Working Smarter with Copilot 🚀</title>
      <dc:creator>Muhammad Hamid Raza</dc:creator>
      <pubDate>Wed, 29 Apr 2026 11:24:49 +0000</pubDate>
      <link>https://dev.to/hamidrazadev/vs-code-1118-is-here-and-its-all-about-working-smarter-with-copilot-56go</link>
      <guid>https://dev.to/hamidrazadev/vs-code-1118-is-here-and-its-all-about-working-smarter-with-copilot-56go</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Released April 29, 2026 — VS Code keeps leveling up, and this one's packed.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You open VS Code, kick off a Copilot agent task, step away from your desk, and come back to find… it's been waiting for your approval the whole time. Frustrating, right?&lt;/p&gt;

&lt;p&gt;VS Code 1.118 is basically Microsoft reading that frustration and going, &lt;em&gt;"Okay, okay, we got you."&lt;/em&gt; This release is laser-focused on making your Copilot workflow faster, smarter, and less tethered to your physical machine. Let's dig in. 👇&lt;/p&gt;




&lt;h2&gt;
  
  
  🎮 Remote Control for Copilot CLI Sessions
&lt;/h2&gt;

&lt;p&gt;This is the headline feature — and it genuinely changes how you run long agent tasks.&lt;/p&gt;

&lt;p&gt;Previously, if your Copilot CLI session hit a pause (waiting for an approval, asking a question), you had to physically be at your machine to respond. Not anymore.&lt;/p&gt;

&lt;p&gt;With &lt;strong&gt;remote control&lt;/strong&gt;, you can monitor and steer active Copilot CLI sessions from &lt;strong&gt;GitHub.com or the GitHub mobile app&lt;/strong&gt; — while the session keeps running in the background on your dev machine. Check progress, respond to approvals, redirect the agent… all from your phone or another device.&lt;/p&gt;

&lt;p&gt;To try it out:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Enable the &lt;code&gt;github.copilot.chat.cli.remote.enabled&lt;/code&gt; setting&lt;/li&gt;
&lt;li&gt;Type &lt;code&gt;/remote on&lt;/code&gt; in a Copilot CLI chat&lt;/li&gt;
&lt;li&gt;That's it — you're now in control from anywhere&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is a big deal for anyone running heavy multi-step agent workflows. No more babysitting your terminal.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔍 Smarter Codebase Search — Now for Everyone
&lt;/h2&gt;

&lt;p&gt;Search in Copilot just got a serious upgrade on two fronts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Semantic indexing is now available in ALL workspaces&lt;/strong&gt; — not just GitHub/ADO repos. So when you ask Copilot something like &lt;em&gt;"where do we handle user authentication?"&lt;/em&gt;, it searches by &lt;em&gt;meaning&lt;/em&gt;, not just literal text. It'll surface files using &lt;code&gt;signIn&lt;/code&gt;, &lt;code&gt;verifyCredentials&lt;/code&gt;, &lt;code&gt;OAuth token exchange&lt;/code&gt;, etc., even if the word "authentication" never appears. The index builds automatically, though non-GitHub workspaces may need a few minutes on first run. You can also trigger it manually with &lt;strong&gt;Build Codebase semantic index&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub text search across repos and orgs&lt;/strong&gt; is the second addition. When you need a precise grep-style match — an exact API name, an error string — semantic search isn't ideal. The new &lt;code&gt;githubTextSearch&lt;/code&gt; agent tool handles exactly that: regex-style search across any GitHub repo or your entire organization. Pair it with the existing &lt;code&gt;githubRepo&lt;/code&gt; semantic tool and Copilot now has a seriously comprehensive understanding of code it hasn't even opened yet.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚡ Token Efficiency — Your Wallet Will Thank You
&lt;/h2&gt;

&lt;p&gt;With GitHub Copilot moving to usage-based billing on June 1, 2026, this section is arguably the most practically important of the entire release.&lt;/p&gt;

&lt;p&gt;The team has shipped multiple improvements to get more done with fewer tokens:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prompt caching is now way more efficient.&lt;/strong&gt; Cache breakpoints are now strategically placed at stable boundaries — end of system prompt, end of tools, end of the most recent tool turn. The result? &lt;strong&gt;Over 93% of each request is reused from cache&lt;/strong&gt; instead of billed as fresh input. That's massive for long, multi-turn agent workflows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Tool Search Tool&lt;/strong&gt; splits the agent's toolset into two groups: a compact always-available core (~30 tools covering 88% of calls), and deferred tools loaded only on demand. Already showing &lt;strong&gt;up to 20% token savings&lt;/strong&gt; for Anthropic models, and now rolling out to supported OpenAI models too.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;New Agentic Search and Execution tools&lt;/strong&gt; are powered by smaller, purpose-built models that cost significantly less to run. The search tool handles codebase exploration independently. The execution tool handles terminal commands (capped at 10 calls per invocation so it can't loop forever) and strips verbose terminal output down to only what the coding agent actually needs. Together: &lt;strong&gt;up to 20% more token savings&lt;/strong&gt; over a month of testing.&lt;/p&gt;

&lt;p&gt;If you're on a Copilot plan, these changes are already quietly saving you budget in the background. Nice.&lt;/p&gt;




&lt;h2&gt;
  
  
  📚 Chronicle — Your Chat History, Actually Useful
&lt;/h2&gt;

&lt;p&gt;Ever tried scrolling back through 3 weeks of Copilot chat sessions trying to remember what you worked on? It's chaos.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Chronicle&lt;/strong&gt; (experimental, behind &lt;code&gt;github.copilot.chat.localIndex.enabled&lt;/code&gt;) fixes this by storing your chat activity in a local SQLite database. Every session logs: branch, repo, timestamps, files touched, and external references like PRs, issues, and commits.&lt;/p&gt;

&lt;p&gt;Then you get three handy slash commands:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;/chronicle:standup&lt;/code&gt; — Auto-generates a standup report from the last 24 hours, grouped by feature/branch, with summaries and PR links 🙌&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/chronicle:tips&lt;/code&gt; — Analyzes 7 days of your usage and gives you personalized tips to improve prompting and tool usage&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/chronicle [query]&lt;/code&gt; — Free-form natural language queries like &lt;em&gt;"what files did I edit yesterday?"&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The standup one alone might justify enabling this feature. No more "uh... I worked on some stuff" moments in your daily sync.&lt;/p&gt;




&lt;h2&gt;
  
  
  🛡️ Enterprise Controls &amp;amp; Security Tightening
&lt;/h2&gt;

&lt;p&gt;A couple of notable changes on the trust and security front.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Approved Account Organizations Policy&lt;/strong&gt; lets enterprises gate all AI feature access behind approved GitHub organization membership. Features simply don't activate until the signed-in account belongs to an approved org and the policy clears. Fail-closed behavior — nothing shows until eligibility is confirmed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sandbox read permissions are now tighter by default.&lt;/strong&gt; Previously, commands running in the sandbox had automatic read access to everything under &lt;code&gt;$HOME&lt;/code&gt;. Now, read permissions are scoped strictly to the executing command's needs. Workspace folders still get access, but arbitrary &lt;code&gt;$HOME&lt;/code&gt; paths are denied by default. A quiet but meaningful security improvement.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧪 TypeScript 7.0 Beta + Other Dev Goodies
&lt;/h2&gt;

&lt;p&gt;TypeScript 7 is a full rewrite in native code, and VS Code 1.118 is making it easier than ever to try the beta.&lt;/p&gt;

&lt;p&gt;For the VS Code team itself, the switch to TS 7 for development builds has been dramatic: full type-checking of ~6,000 files dropped from &lt;strong&gt;~60 seconds to ~10 seconds&lt;/strong&gt;. The entire build + typecheck cycle now takes around 30 seconds total. That's not just impressive — that's life-changing for contributor DX.&lt;/p&gt;

&lt;p&gt;You can try TS 7.0 Beta right now by installing the &lt;strong&gt;TypeScript Native Preview&lt;/strong&gt; extension. Switching back to stable TS 6 is just as easy.&lt;/p&gt;

&lt;p&gt;A few other notable additions this release:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;WebSockets for OpenAI models&lt;/strong&gt; — persistent connections instead of new HTTP requests per turn, making OpenAI models about &lt;strong&gt;12% faster&lt;/strong&gt; in agent workflows&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dev Container lockfile enabled by default&lt;/strong&gt; — pins Feature versions and checksums to protect against supply chain attacks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optimized large resource loading in webviews&lt;/strong&gt; — file contents now stream in chunks instead of loading entirely into memory, which matters a lot when you're loading big video files in a notebook&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🎯 Wrap-Up — The Efficiency Update
&lt;/h2&gt;

&lt;p&gt;VS Code 1.118 isn't about flashy new UI tricks. It's about efficiency — token efficiency, workflow efficiency, and making the AI-assisted development experience genuinely less friction-y.&lt;/p&gt;

&lt;p&gt;Remote CLI control, smarter search, Chronicle for history, tighter sandbox security, and TypeScript 7 performance improvements all point to the same theme: &lt;strong&gt;VS Code is getting out of your way and letting you move faster.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The token efficiency work especially deserves recognition — the team shipped real, measurable savings right before usage-based billing kicks in. That's not an accident.&lt;/p&gt;

&lt;p&gt;Update today via &lt;strong&gt;Help → Check for Updates&lt;/strong&gt;, or grab the &lt;a href="https://code.visualstudio.com/insiders/" rel="noopener noreferrer"&gt;VS Code Insiders build&lt;/a&gt; to get bleeding-edge features the moment they drop.&lt;/p&gt;

&lt;p&gt;Happy Coding! 💻&lt;/p&gt;




&lt;h2&gt;
  
  
  📌 Quick Reference — Key Features at a Glance
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;th&gt;Setting / Command&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Remote Copilot CLI control&lt;/td&gt;
&lt;td&gt;Experimental&lt;/td&gt;
&lt;td&gt;&lt;code&gt;github.copilot.chat.cli.remote.enabled&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Semantic indexing (all repos)&lt;/td&gt;
&lt;td&gt;✅ Live for everyone&lt;/td&gt;
&lt;td&gt;Auto / &lt;code&gt;Build Codebase semantic index&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GitHub text search (orgs)&lt;/td&gt;
&lt;td&gt;✅ Live&lt;/td&gt;
&lt;td&gt;Built-in &lt;code&gt;githubTextSearch&lt;/code&gt; tool&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tool Search Tool (OpenAI)&lt;/td&gt;
&lt;td&gt;Rolling out&lt;/td&gt;
&lt;td&gt;&lt;code&gt;github.copilot.chat.responsesApi.toolSearchTool.enabled&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Chronicle (chat history)&lt;/td&gt;
&lt;td&gt;Experimental&lt;/td&gt;
&lt;td&gt;&lt;code&gt;github.copilot.chat.localIndex.enabled&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TypeScript 7.0 Beta&lt;/td&gt;
&lt;td&gt;Preview&lt;/td&gt;
&lt;td&gt;Install &lt;em&gt;TypeScript Native Preview&lt;/em&gt; extension&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dev Container lockfile&lt;/td&gt;
&lt;td&gt;✅ Default ON&lt;/td&gt;
&lt;td&gt;&lt;code&gt;dev.containers.lockfile&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;p&gt;&lt;em&gt;Found this useful? Drop a reaction and share it with your dev squad. More VS Code deep-dives coming soon. 🔔&lt;/em&gt;&lt;/p&gt;

</description>
      <category>vscode</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>productivity</category>
    </item>
    <item>
      <title>How to Build a Drag-and-Drop File Dropzone in React &amp; Next.js (With Tailwind CSS) — Line by Line</title>
      <dc:creator>Muhammad Hamid Raza</dc:creator>
      <pubDate>Wed, 29 Apr 2026 07:33:04 +0000</pubDate>
      <link>https://dev.to/hamidrazadev/how-to-build-a-drag-and-drop-file-dropzone-in-react-nextjs-with-tailwind-css-line-by-line-3c6g</link>
      <guid>https://dev.to/hamidrazadev/how-to-build-a-drag-and-drop-file-dropzone-in-react-nextjs-with-tailwind-css-line-by-line-3c6g</guid>
      <description>&lt;p&gt;Ever tried to upload a file on a website and the experience felt like dragging a suitcase up a broken escalator? 😅 A clunky &lt;code&gt;&amp;lt;input type="file"&amp;gt;&lt;/code&gt; button just doesn't cut it anymore. Users expect a smooth, modern &lt;strong&gt;drag-and-drop experience&lt;/strong&gt; — and as a developer, you should know how to build one.&lt;/p&gt;

&lt;p&gt;In this post, we're going to build a &lt;strong&gt;fully functional, reusable Dropzone component&lt;/strong&gt; in React (works in Next.js too) styled beautifully with &lt;strong&gt;Tailwind CSS&lt;/strong&gt;. Every single line of code will be explained so you know exactly what's happening and why.&lt;/p&gt;

&lt;p&gt;Ready to make file uploading feel like a superpower? Let's go. 🚀&lt;/p&gt;




&lt;h2&gt;
  
  
  What Is a Dropzone?
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;Dropzone&lt;/strong&gt; is a UI area where users can either &lt;strong&gt;drag and drop files&lt;/strong&gt; or &lt;strong&gt;click to browse&lt;/strong&gt; files from their device. Think of it like a designated landing pad — you either drop the package from above or walk up and hand it in.&lt;/p&gt;

&lt;p&gt;Instead of just clicking a tiny "Choose File" button, users can grab a file from their desktop and drop it directly into a highlighted area on the page. It's more intuitive, more visual, and honestly just looks much better.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Build Your Own Dropzone?
&lt;/h2&gt;

&lt;p&gt;You might be thinking: &lt;em&gt;"Can't I just use react-dropzone?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You absolutely can. But knowing how to build one from scratch means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You understand the browser's &lt;strong&gt;Drag-and-Drop API&lt;/strong&gt; deeply&lt;/li&gt;
&lt;li&gt;You're not adding unnecessary npm packages for simple use cases&lt;/li&gt;
&lt;li&gt;You can customize every pixel and every behavior&lt;/li&gt;
&lt;li&gt;You can extend it however you need — file previews, progress bars, validations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And honestly, after this post, using any library will make even more sense because you'll understand what's happening under the hood.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Matters for Real Projects
&lt;/h2&gt;

&lt;p&gt;Here are situations where a good Dropzone actually matters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Profile picture uploads&lt;/strong&gt; — Instagram-style image selection&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Document upload portals&lt;/strong&gt; — legal, medical, or HR apps&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Portfolio builders&lt;/strong&gt; — drag project screenshots in&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Form builders&lt;/strong&gt; — attach files to a contact or support form&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI tools&lt;/strong&gt; — let users upload images or PDFs to analyze&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A broken or ugly file upload experience kills trust fast. A smooth one builds it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Benefits of a Custom Dropzone Component
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;✅ &lt;strong&gt;Reusable&lt;/strong&gt; — Build once, use everywhere in your project&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Fully controlled&lt;/strong&gt; — You decide what file types are accepted&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Visual feedback&lt;/strong&gt; — Users see drag state, file name, errors&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;No extra dependencies&lt;/strong&gt; — Pure React + Tailwind&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Accessible&lt;/strong&gt; — Works with click too, not just drag&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Next.js compatible&lt;/strong&gt; — Just add &lt;code&gt;"use client"&lt;/code&gt; and you're good&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Complete Copy-Paste Component
&lt;/h2&gt;

&lt;p&gt;Before we explain everything line by line, here's the &lt;strong&gt;complete component&lt;/strong&gt; you can copy-paste directly into your project. Just drop it in your &lt;code&gt;components/&lt;/code&gt; folder as &lt;code&gt;Dropzone.jsx&lt;/code&gt; (or &lt;code&gt;Dropzone.tsx&lt;/code&gt; for TypeScript users).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;use client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Required in Next.js App Router to enable React hooks&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useCallback&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Dropzone&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;onFilesSelected&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;accept&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;multiple&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isDragging&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setIsDragging&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;droppedFiles&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setDroppedFiles&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;inputRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;validateFiles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;multiple&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Only one file is allowed.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;accept&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;allowedTypes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;accept&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;allValid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;every&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
          &lt;span class="nx"&gt;allowedTypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;some&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;endsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;allValid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nf"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Invalid file type. Allowed: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;accept&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nf"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;accept&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;multiple&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleFiles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fileArray&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;validateFiles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fileArray&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nf"&gt;setDroppedFiles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fileArray&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;onFilesSelected&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;onFilesSelected&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fileArray&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;validateFiles&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onFilesSelected&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleDragOver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stopPropagation&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nf"&gt;setIsDragging&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleDragLeave&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stopPropagation&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nf"&gt;setIsDragging&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleDrop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stopPropagation&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nf"&gt;setIsDragging&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dataTransfer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;handleFiles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleClick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;inputRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleInputChange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;handleFiles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleRemoveFile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;updated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;droppedFiles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;setDroppedFiles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updated&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;onFilesSelected&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;onFilesSelected&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updated&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"w-full max-w-xl mx-auto"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Dropzone Area */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;
        &lt;span class="na"&gt;onDragOver&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleDragOver&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;onDragLeave&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleDragLeave&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;onDrop&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleDrop&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleClick&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`
          flex flex-col items-center justify-center
          border-2 border-dashed rounded-2xl
          p-10 cursor-pointer transition-all duration-300
          &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;isDragging&lt;/span&gt;
            &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;border-orange-400 bg-orange-50 scale-[1.02]&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
            &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;border-gray-300 bg-gray-50 hover:border-orange-300 hover:bg-orange-50&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;
        `&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Icon */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"mb-4 text-5xl select-none"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isDragging&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;📂&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;📁&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Text */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text-gray-600 text-base font-medium text-center"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isDragging&lt;/span&gt;
            &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Release to drop your files here!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
            &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Drag &amp;amp; drop files here, or click to browse&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text-gray-400 text-sm mt-1 text-center"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;accept&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;All file types accepted&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Accepted: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;accept&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Hidden File Input */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
          &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;inputRef&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"file"&lt;/span&gt;
          &lt;span class="na"&gt;accept&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;accept&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;multiple&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;multiple&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"hidden"&lt;/span&gt;
          &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleInputChange&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Error Message */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"mt-3 text-sm text-red-500 font-medium text-center"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          ⚠️ &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;

      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* File List */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;droppedFiles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"mt-4 space-y-2"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;droppedFiles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;
              &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
              &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"flex items-center justify-between bg-white border border-gray-200 rounded-xl px-4 py-3 shadow-sm"&lt;/span&gt;
            &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"flex items-center gap-3 overflow-hidden"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text-xl"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;📄&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"overflow-hidden"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text-sm font-medium text-gray-700 truncate"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text-xs text-gray-400"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; KB&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;
                &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                  &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stopPropagation&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
                  &lt;span class="nf"&gt;handleRemoveFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"ml-4 text-gray-400 hover:text-red-500 transition-colors text-lg font-bold"&lt;/span&gt;
                &lt;span class="na"&gt;aria-label&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Remove file"&lt;/span&gt;
              &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                ×
              &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  How to Use the Component
&lt;/h2&gt;

&lt;p&gt;Paste this wherever you want in your page or form:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// pages/index.jsx or app/page.jsx&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Dropzone&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@/components/Dropzone&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Home&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleFiles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Selected files:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// Send to server, preview, etc.&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"min-h-screen flex items-center justify-center bg-gray-100 p-6"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Dropzone&lt;/span&gt;
        &lt;span class="na"&gt;onFilesSelected&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleFiles&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;accept&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"image/png, image/jpeg, image/webp"&lt;/span&gt;
        &lt;span class="na"&gt;multiple&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. Drop images in — you'll see them listed below the zone. 🎉&lt;/p&gt;




&lt;h2&gt;
  
  
  Line-by-Line Code Explanation
&lt;/h2&gt;

&lt;p&gt;Now let's break down &lt;strong&gt;every important part&lt;/strong&gt; of the component so you understand the "why" behind each line.&lt;/p&gt;




&lt;h3&gt;
  
  
  1. &lt;code&gt;"use client"&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;use client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is &lt;strong&gt;Next.js App Router specific&lt;/strong&gt;. It tells Next.js that this component runs in the browser, not on the server. You need this because we use React hooks like &lt;code&gt;useState&lt;/code&gt; and event listeners. If you're using Next.js Pages Router or plain React, you can remove this line — it's not needed there.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Importing Hooks
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useCallback&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;useState&lt;/code&gt;&lt;/strong&gt; — manages state: is the user dragging? what files are dropped? any errors?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;useRef&lt;/code&gt;&lt;/strong&gt; — creates a direct reference to the hidden &lt;code&gt;&amp;lt;input type="file"&amp;gt;&lt;/code&gt; element so we can trigger it programmatically when the user clicks anywhere on the dropzone&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;useCallback&lt;/code&gt;&lt;/strong&gt; — wraps functions so they don't get recreated on every re-render, which is important when those functions are used as dependencies in other hooks&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  3. Component Props
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Dropzone&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;onFilesSelected&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;accept&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;multiple&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;onFilesSelected&lt;/code&gt;&lt;/strong&gt; — a callback function the parent passes in to receive the selected files. Think of it like handing a delivery to the right address.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;accept&lt;/code&gt;&lt;/strong&gt; — which file types are allowed. Defaults to &lt;code&gt;"*"&lt;/code&gt; meaning anything goes. You can pass &lt;code&gt;"image/png, image/jpeg"&lt;/code&gt; to restrict to images.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;multiple&lt;/code&gt;&lt;/strong&gt; — if &lt;code&gt;true&lt;/code&gt;, user can select multiple files. Default is &lt;code&gt;false&lt;/code&gt; (single file only).&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  4. State Variables
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isDragging&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setIsDragging&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;droppedFiles&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setDroppedFiles&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;inputRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;isDragging&lt;/code&gt;&lt;/strong&gt; — tracks whether a file is currently being dragged over the dropzone. Used to change the visual appearance dynamically.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;droppedFiles&lt;/code&gt;&lt;/strong&gt; — stores the list of files the user has dropped or selected. This is what gets shown in the file list below.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;error&lt;/code&gt;&lt;/strong&gt; — stores any validation error message (like "wrong file type").&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;inputRef&lt;/code&gt;&lt;/strong&gt; — points directly to the hidden &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt; element. When the user clicks the dropzone, we call &lt;code&gt;inputRef.current.click()&lt;/code&gt; to open the file picker — even though the input itself is invisible.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  5. The &lt;code&gt;validateFiles&lt;/code&gt; Function
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;validateFiles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;multiple&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Only one file is allowed.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;accept&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;allowedTypes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;accept&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;allValid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;every&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="nx"&gt;allowedTypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;some&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;endsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;allValid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Invalid file type. Allowed: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;accept&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;accept&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;multiple&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;This is your security guard.&lt;/strong&gt; 🔒&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If &lt;code&gt;multiple&lt;/code&gt; is &lt;code&gt;false&lt;/code&gt; but the user dropped 3 files, it rejects immediately with an error message.&lt;/li&gt;
&lt;li&gt;Then it checks file types. It splits the &lt;code&gt;accept&lt;/code&gt; string (e.g., &lt;code&gt;"image/png, image/jpeg"&lt;/code&gt;) into an array and checks whether each file matches.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;.every()&lt;/code&gt; means &lt;strong&gt;all files&lt;/strong&gt; must pass. One bad apple ruins the whole batch.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;file.type&lt;/code&gt; checks the MIME type (e.g., &lt;code&gt;"image/png"&lt;/code&gt;). &lt;code&gt;file.name.endsWith(type)&lt;/code&gt; is a fallback for checking extensions (e.g., &lt;code&gt;.pdf&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;If everything's fine, it clears the error and returns &lt;code&gt;true&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  6. The &lt;code&gt;handleFiles&lt;/code&gt; Function
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleFiles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fileArray&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;validateFiles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fileArray&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nf"&gt;setDroppedFiles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fileArray&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;onFilesSelected&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;onFilesSelected&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fileArray&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;validateFiles&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onFilesSelected&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the &lt;strong&gt;central dispatcher&lt;/strong&gt; for all file activity — whether the user drags, drops, or clicks to pick files.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Array.from(files)&lt;/code&gt; converts the native &lt;code&gt;FileList&lt;/code&gt; object (what the browser gives you) into a regular JavaScript array. FileList is not an array, so you can't use &lt;code&gt;.map()&lt;/code&gt; or &lt;code&gt;.filter()&lt;/code&gt; on it directly.&lt;/li&gt;
&lt;li&gt;It runs validation first. If validation fails, it stops right there — &lt;code&gt;return&lt;/code&gt; exits the function.&lt;/li&gt;
&lt;li&gt;If files pass validation, it saves them in state and calls the parent's &lt;code&gt;onFilesSelected&lt;/code&gt; callback so the parent knows what files were selected.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  7. &lt;code&gt;handleDragOver&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleDragOver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stopPropagation&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nf"&gt;setIsDragging&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This fires &lt;strong&gt;continuously&lt;/strong&gt; as the user hovers a file over the dropzone.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;e.preventDefault()&lt;/code&gt; is &lt;strong&gt;critical&lt;/strong&gt;. Without it, the browser would open the file itself (imagine dropping a PDF and suddenly the browser navigates to a PDF viewer). This stops that default behavior.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;e.stopPropagation()&lt;/code&gt; prevents the event from bubbling up to parent elements, which could cause unexpected behavior.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;setIsDragging(true)&lt;/code&gt; activates the "active drag" visual state.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  8. &lt;code&gt;handleDragLeave&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleDragLeave&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stopPropagation&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nf"&gt;setIsDragging&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fires when the user's dragged file &lt;strong&gt;leaves&lt;/strong&gt; the dropzone area. Sets &lt;code&gt;isDragging&lt;/code&gt; back to &lt;code&gt;false&lt;/code&gt; so the highlighted state disappears. Simple but necessary.&lt;/p&gt;




&lt;h3&gt;
  
  
  9. &lt;code&gt;handleDrop&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleDrop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stopPropagation&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nf"&gt;setIsDragging&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dataTransfer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;handleFiles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This fires when the user &lt;strong&gt;releases&lt;/strong&gt; the file over the dropzone.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Again, &lt;code&gt;e.preventDefault()&lt;/code&gt; prevents the browser from opening the file.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;e.dataTransfer.files&lt;/code&gt; is where the browser stores the dropped files. &lt;code&gt;dataTransfer&lt;/code&gt; is the native browser API specifically for drag-and-drop data.&lt;/li&gt;
&lt;li&gt;We check that files exist and are not empty, then pass them to &lt;code&gt;handleFiles&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  10. &lt;code&gt;handleClick&lt;/code&gt; and &lt;code&gt;handleInputChange&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleClick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;inputRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleInputChange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;handleFiles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;handleClick&lt;/code&gt; programmatically triggers a click on the hidden &lt;code&gt;&amp;lt;input type="file"&amp;gt;&lt;/code&gt;. The &lt;code&gt;?.&lt;/code&gt; is optional chaining — just in case the ref hasn't attached yet.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;handleInputChange&lt;/code&gt; handles files selected through the file picker dialog. &lt;code&gt;e.target.files&lt;/code&gt; gives us the FileList from the native input.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both paths — drag-drop and click-to-browse — eventually call the same &lt;code&gt;handleFiles&lt;/code&gt; function. Single source of truth. ✅&lt;/p&gt;




&lt;h3&gt;
  
  
  11. &lt;code&gt;handleRemoveFile&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleRemoveFile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;updated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;droppedFiles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;setDroppedFiles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updated&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;onFilesSelected&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;onFilesSelected&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updated&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Removes a file from the list by index. The &lt;code&gt;filter&lt;/code&gt; creates a new array excluding the file at the given index. We also notify the parent with the updated list via &lt;code&gt;onFilesSelected&lt;/code&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  12. The JSX — Dropzone Area
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;
  &lt;span class="na"&gt;onDragOver&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleDragOver&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;onDragLeave&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleDragLeave&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;onDrop&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleDrop&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleClick&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`
    flex flex-col items-center justify-center
    border-2 border-dashed rounded-2xl
    p-10 cursor-pointer transition-all duration-300
    &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;isDragging&lt;/span&gt;
      &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;border-orange-400 bg-orange-50 scale-[1.02]&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;border-gray-300 bg-gray-50 hover:border-orange-300 hover:bg-orange-50&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;
  `&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This &lt;code&gt;div&lt;/code&gt; is the &lt;strong&gt;entire interactive surface&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Four event listeners handle dragging, leaving, dropping, and clicking.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;flex flex-col items-center justify-center&lt;/code&gt; — centers everything inside vertically and horizontally.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;border-2 border-dashed&lt;/code&gt; — the classic dropzone dashed border look.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;rounded-2xl&lt;/code&gt; — smooth, modern rounded corners.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;cursor-pointer&lt;/code&gt; — signals to the user that this area is clickable.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;transition-all duration-300&lt;/code&gt; — smooth visual transitions when state changes.&lt;/li&gt;
&lt;li&gt;The conditional class: when &lt;code&gt;isDragging&lt;/code&gt; is &lt;code&gt;true&lt;/code&gt;, the border goes orange, the background gets a soft orange tint, and the box subtly scales up (&lt;code&gt;scale-[1.02]&lt;/code&gt;). It gives satisfying visual feedback that "yes, you can drop here."&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  13. The Hidden Input
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
  &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;inputRef&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"file"&lt;/span&gt;
  &lt;span class="na"&gt;accept&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;accept&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;multiple&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;multiple&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"hidden"&lt;/span&gt;
  &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleInputChange&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ref={inputRef}&lt;/code&gt; — connects this element to our &lt;code&gt;inputRef&lt;/code&gt; so we can trigger it from &lt;code&gt;handleClick&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;type="file"&lt;/code&gt; — standard HTML file input.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;accept&lt;/code&gt; and &lt;code&gt;multiple&lt;/code&gt; are passed from props, controlling what's allowed.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;className="hidden"&lt;/code&gt; — the input is invisible. The &lt;code&gt;div&lt;/code&gt; above acts as the visual replacement.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;onChange&lt;/code&gt; — fires when the user selects files via the file picker dialog.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  14. File List
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;droppedFiles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"flex items-center justify-between bg-white border border-gray-200 rounded-xl px-4 py-3 shadow-sm"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    ...
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text-sm font-medium text-gray-700 truncate"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text-xs text-gray-400"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; KB&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    ...
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;))}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;We loop over &lt;code&gt;droppedFiles&lt;/code&gt; and render each one as a list item.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;file.name&lt;/code&gt; gives the original filename.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;file.size&lt;/code&gt; is in bytes, so we divide by &lt;code&gt;1024&lt;/code&gt; to convert to KB and use &lt;code&gt;.toFixed(1)&lt;/code&gt; to show one decimal place.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;truncate&lt;/code&gt; is a Tailwind class that adds &lt;code&gt;text-overflow: ellipsis&lt;/code&gt; — long filenames won't break the layout.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  15. The Remove Button
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;
  &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stopPropagation&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nf"&gt;handleRemoveFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="err"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  ×
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;e.stopPropagation()&lt;/code&gt; here is &lt;strong&gt;important&lt;/strong&gt;. Without it, clicking the remove button would also trigger the parent &lt;code&gt;div&lt;/code&gt;'s &lt;code&gt;onClick&lt;/code&gt;, which would open the file picker. We stop the click from bubbling up.&lt;/p&gt;




&lt;h2&gt;
  
  
  Comparison: Native Input vs Custom Dropzone
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;&lt;code&gt;&amp;lt;input type="file"&amp;gt;&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;Custom Dropzone&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Drag &amp;amp; Drop&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Visual feedback&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File preview&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Custom styling&lt;/td&gt;
&lt;td&gt;Very limited&lt;/td&gt;
&lt;td&gt;Fully customizable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Remove individual files&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File type validation&lt;/td&gt;
&lt;td&gt;Basic&lt;/td&gt;
&lt;td&gt;Custom &amp;amp; detailed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;UX quality&lt;/td&gt;
&lt;td&gt;Basic&lt;/td&gt;
&lt;td&gt;Modern &amp;amp; polished&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Best Tips — Do's &amp;amp; Don'ts
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;✅ Do's:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Always call &lt;code&gt;e.preventDefault()&lt;/code&gt; on &lt;code&gt;dragover&lt;/code&gt; and &lt;code&gt;drop&lt;/code&gt;. Without it, the browser does its own thing.&lt;/li&gt;
&lt;li&gt;Convert &lt;code&gt;FileList&lt;/code&gt; to an array before doing anything useful with it.&lt;/li&gt;
&lt;li&gt;Give clear visual feedback when the user is dragging over the zone.&lt;/li&gt;
&lt;li&gt;Always notify the parent component via a callback so it can handle uploads.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;e.stopPropagation()&lt;/code&gt; on nested click handlers to prevent accidental triggers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;❌ Don'ts:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Don't forget &lt;code&gt;"use client"&lt;/code&gt; in Next.js App Router. Hooks won't work without it.&lt;/li&gt;
&lt;li&gt;Don't rely only on &lt;code&gt;file.type&lt;/code&gt; for validation — it can be spoofed. Always validate on the server too.&lt;/li&gt;
&lt;li&gt;Don't skip the &lt;code&gt;multiple&lt;/code&gt; prop logic if your backend only accepts one file.&lt;/li&gt;
&lt;li&gt;Don't make the dropzone too small — users need room to drop.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Common Mistakes People Make
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Forgetting &lt;code&gt;e.preventDefault()&lt;/code&gt; on &lt;code&gt;dragover&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is the most common mistake. If you skip it, the drop event will never fire because the browser cancels it. Every drag-and-drop implementation needs this.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Not converting &lt;code&gt;FileList&lt;/code&gt; to an Array&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;FileList&lt;/code&gt; is a browser-native object. It looks like an array but it's not. Calling &lt;code&gt;.map()&lt;/code&gt; or &lt;code&gt;.filter()&lt;/code&gt; directly on it will throw an error. Always use &lt;code&gt;Array.from(files)&lt;/code&gt; first.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Skipping the &lt;code&gt;stopPropagation&lt;/code&gt; on the remove button&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If the remove button click bubbles up to the parent &lt;code&gt;div&lt;/code&gt;, it also triggers the file picker. Very confusing for users. Always stop it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Only supporting drag-and-drop but not click&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Some users (especially on trackpads) find drag-and-drop annoying or harder. Always support both interactions. Our component does this — clicking anywhere on the zone opens the file picker.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Doing validation only on the frontend&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Frontend validation is for UX. Server-side validation is for security. Never trust a file just because the browser said it was valid. Always re-validate on the backend.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Building a custom Dropzone component from scratch is one of those things that teaches you a lot in a short amount of time. You learn about the browser's Drag-and-Drop API, React state management, refs, callbacks, and Tailwind styling — all in one component. 🎯&lt;/p&gt;

&lt;p&gt;Here's what we covered:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How drag-and-drop events work in the browser&lt;/li&gt;
&lt;li&gt;How to build a reusable Dropzone component with clean props&lt;/li&gt;
&lt;li&gt;How Tailwind classes make visual state changes effortless&lt;/li&gt;
&lt;li&gt;How to validate files, remove them, and pass them to the parent&lt;/li&gt;
&lt;li&gt;What every single line is doing and why it's there&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now you have a clean, copy-paste-ready Dropzone component that you can drop into any React or Next.js project and customize to your heart's content.&lt;/p&gt;

&lt;p&gt;Want more practical React and Next.js tutorials like this one? Head over to &lt;strong&gt;&lt;a href="https://hamidrazadev.com" rel="noopener noreferrer"&gt;hamidrazadev.com&lt;/a&gt;&lt;/strong&gt; — there's a lot more waiting for you there. 💡&lt;/p&gt;

&lt;p&gt;If this post saved you time or cleared up confusion, share it with a dev friend or your team. They'll thank you for it. 😊&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>react</category>
      <category>tailwindcss</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How Pagination Works — And Why Every Developer Needs to Understand It 📄</title>
      <dc:creator>Muhammad Hamid Raza</dc:creator>
      <pubDate>Tue, 28 Apr 2026 09:47:04 +0000</pubDate>
      <link>https://dev.to/hamidrazadev/how-pagination-works-and-why-every-developer-needs-to-understand-it-4k6d</link>
      <guid>https://dev.to/hamidrazadev/how-pagination-works-and-why-every-developer-needs-to-understand-it-4k6d</guid>
      <description>&lt;p&gt;You open an app. It loads 10,000 records all at once. Your browser freezes. Your users leave. 😬&lt;/p&gt;

&lt;p&gt;Sound familiar? That's the pagination problem in reverse — what happens when you &lt;em&gt;don't&lt;/em&gt; use it. Pagination is one of those concepts that looks simple on the surface but quietly powers almost every real-world app you've ever used: Google Search, Twitter feeds, product listings, admin dashboards, and more.&lt;/p&gt;

&lt;p&gt;So how does it actually work? And how do you build it? Let's break it all down from scratch — with a real React component at the end.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Is Pagination?
&lt;/h2&gt;

&lt;p&gt;Imagine you walk into a library and ask the librarian for &lt;em&gt;every book they have&lt;/em&gt;. She stares at you. There are 50,000 books. You clearly can't carry them all at once.&lt;/p&gt;

&lt;p&gt;So instead, she says: "I'll bring you 10 books at a time. Tell me which shelf to start from."&lt;/p&gt;

&lt;p&gt;That's pagination.&lt;/p&gt;

&lt;p&gt;In software, &lt;strong&gt;pagination is the process of splitting a large dataset into smaller chunks (pages) and delivering one chunk at a time.&lt;/strong&gt; Instead of loading 10,000 rows from your database into the browser at once, you load page 1 (rows 1–10), then page 2 (rows 11–20), and so on — only when the user asks.&lt;/p&gt;

&lt;p&gt;The user controls which "shelf" they want. The server (or your frontend) delivers just that shelf.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Pagination Matters
&lt;/h2&gt;

&lt;p&gt;Without pagination, your app has a few serious problems:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Performance tanks.&lt;/strong&gt; Fetching thousands of records at once is slow. Rendering them is even slower. The browser has to process, paint, and hold all of that in memory — for data the user probably won't even scroll to.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;APIs get overwhelmed.&lt;/strong&gt; Your backend server has to query the entire database, serialize everything, and send it over the network. For large datasets, this can take seconds or even crash the server.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;UX suffers.&lt;/strong&gt; A page that loads slowly or shows an endless wall of data is a bad experience. Users bounce. They don't stay.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Costs go up.&lt;/strong&gt; If you're using a cloud database or API with metered billing, loading unnecessary data wastes money directly.&lt;/p&gt;

&lt;p&gt;Pagination solves all of this by asking a simple question on every data request: &lt;em&gt;"Which page? How many items per page?"&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Benefits of Pagination — With Real Examples
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;⚡ Faster load times&lt;/strong&gt; — An e-commerce store showing 50,000 products loads the first 20 instantly instead of stalling for 10 seconds. Users can start browsing right away.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;📉 Lower server load&lt;/strong&gt; — A &lt;code&gt;SELECT * FROM orders&lt;/code&gt; query on a 2-million-row table is painful. &lt;code&gt;SELECT * FROM orders LIMIT 20 OFFSET 0&lt;/code&gt; is fast and surgical.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;💾 Lower memory usage&lt;/strong&gt; — Your React component doesn't need to store 10,000 items in state. It stores 10 or 20 at a time — clean and efficient.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;🔍 Better UX&lt;/strong&gt; — Users know where they are ("Page 3 of 47"). They can navigate, go back, bookmark a page, and share a specific page URL — like Google search results.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;📊 Easier debugging&lt;/strong&gt; — When your data is paginated, you can isolate a specific page during testing instead of scrolling through thousands of rows.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;🔗 Shareable URLs&lt;/strong&gt; — With query-based pagination like &lt;code&gt;?page=3&lt;/code&gt;, users can share a direct link to a specific page. That's huge for support teams, admins, and product listings.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Types of Pagination
&lt;/h2&gt;

&lt;p&gt;Not all pagination works the same way. There are three common approaches:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Offset-Based Pagination (Classic)
&lt;/h3&gt;

&lt;p&gt;This is the most common and beginner-friendly method. You specify a &lt;code&gt;page&lt;/code&gt; number and a &lt;code&gt;limit&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET /api/posts?page=2&amp;amp;limit=10
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On the backend, this translates to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;posts&lt;/span&gt; &lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="k"&gt;OFFSET&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;OFFSET = (page - 1) × limit&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Simple, predictable, and easy to implement. This is what most tutorials (and this post) use.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Downsides:&lt;/strong&gt; If new items are inserted while a user is paginating, they might skip or see duplicate items. For most apps, this is fine.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Cursor-Based Pagination
&lt;/h3&gt;

&lt;p&gt;Instead of a page number, you use a "cursor" — usually the ID of the last item you saw.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET /api/posts?after=post_id_99&amp;amp;limit=10
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is what Twitter, Instagram, and most social feeds use. It's more stable for real-time data because it doesn't break when new items are added.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Downsides:&lt;/strong&gt; Users can't jump to "page 5" directly. It's sequential — next/previous only.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Frontend (Client-Side) Pagination
&lt;/h3&gt;

&lt;p&gt;All the data is fetched at once, but the display is split into pages on the frontend using JavaScript. This works well for small datasets (under a few hundred items) where a full API call is acceptable.&lt;/p&gt;

&lt;p&gt;No backend changes needed — just slice the array.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;currentPageData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;allData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;startIndex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;endIndex&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the approach we'll use in the component below.&lt;/p&gt;




&lt;h2&gt;
  
  
  Offset Pagination vs Cursor Pagination
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Offset Pagination&lt;/th&gt;
&lt;th&gt;Cursor Pagination&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Jump to any page&lt;/td&gt;
&lt;td&gt;✅ Yes&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Works with real-time data&lt;/td&gt;
&lt;td&gt;⚠️ Not ideal&lt;/td&gt;
&lt;td&gt;✅ Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Easy to implement&lt;/td&gt;
&lt;td&gt;✅ Very&lt;/td&gt;
&lt;td&gt;⚠️ More complex&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Good for static datasets&lt;/td&gt;
&lt;td&gt;✅ Great&lt;/td&gt;
&lt;td&gt;✅ Also fine&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Common in admin panels&lt;/td&gt;
&lt;td&gt;✅ Very common&lt;/td&gt;
&lt;td&gt;Rare&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Common in social feeds&lt;/td&gt;
&lt;td&gt;Rare&lt;/td&gt;
&lt;td&gt;✅ Very common&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Rule of thumb:&lt;/strong&gt; Use offset pagination for dashboards, admin panels, and product listings. Use cursor pagination for live feeds and real-time data.&lt;/p&gt;




&lt;h2&gt;
  
  
  How to Build a Pagination Component in React
&lt;/h2&gt;

&lt;p&gt;Let's build a clean, reusable pagination component with fake data — no external library needed. Just React and a little logic.&lt;/p&gt;

&lt;h3&gt;
  
  
  The logic behind it
&lt;/h3&gt;

&lt;p&gt;Given:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;totalItems&lt;/code&gt; — total number of records&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;itemsPerPage&lt;/code&gt; — how many to show per page&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;currentPage&lt;/code&gt; — the active page&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can calculate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;totalPages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ceil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;totalItems&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;itemsPerPage&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;startIndex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentPage&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;itemsPerPage&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;endIndex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;startIndex&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;itemsPerPage&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;currentData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;startIndex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;endIndex&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Simple math. That's the whole engine.&lt;/p&gt;




&lt;h3&gt;
  
  
  Full Pagination Component
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// --- Fake data to simulate a list of blog posts ---&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;generatePosts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;47&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Blog Post #&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;category&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;React&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;CSS&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;JavaScript&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Next.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Node.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`April &lt;/span&gt;&lt;span class="p"&gt;${(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;28&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, 2025`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}));&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ITEMS_PER_PAGE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// --- Pagination Controls Component ---&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;PaginationControls&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;currentPage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;totalPages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onPageChange&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;totalPages&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flex&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;gap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;8px&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;alignItems&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;center&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;flexWrap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;wrap&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;marginTop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;24px&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;
        &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;onPageChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentPage&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;currentPage&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;btnStyle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentPage&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        ← Prev
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;pages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;
          &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;onPageChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;btnStyle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;currentPage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;

      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;
        &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;onPageChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentPage&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;currentPage&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;totalPages&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;btnStyle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentPage&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;totalPages&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        Next →
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// --- Button styles helper ---&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;btnStyle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;disabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;active&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;8px 14px&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;borderRadius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;6px&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1px solid #ddd&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;disabled&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;not-allowed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pointer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;backgroundColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;active&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#fd6e4e&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;disabled&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#f0f0f0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#fff&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;active&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#fff&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;disabled&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#aaa&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#333&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;fontWeight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;active&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bold&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;normal&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;all 0.2s&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// --- Main App ---&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;PaginatedList&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;currentPage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setCurrentPage&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;allPosts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generatePosts&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;totalPages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ceil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;allPosts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;ITEMS_PER_PAGE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;startIndex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentPage&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;ITEMS_PER_PAGE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;currentPosts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;allPosts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;startIndex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;startIndex&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;ITEMS_PER_PAGE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handlePageChange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;totalPages&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setCurrentPage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;maxWidth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;640px&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;40px auto&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;fontFamily&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sans-serif&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0 16px&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;marginBottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;4px&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;📚 Blog Posts&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#666&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;fontSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;14px&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;marginBottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;20px&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        Showing &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;startIndex&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;–&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;startIndex&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;ITEMS_PER_PAGE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;allPosts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; of &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;allPosts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; posts
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;currentPosts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;
          &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;16px&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;marginBottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;12px&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1px solid #eee&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;borderRadius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;10px&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flex&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;justifyContent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;space-between&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;alignItems&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;center&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;strong&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;strong&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;4px 0 0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;fontSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;13px&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#888&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;
            &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="na"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#fff3ee&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#fd6e4e&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;4px 10px&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;borderRadius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;20px&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;fontSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;12px&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;fontWeight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bold&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;

      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;PaginationControls&lt;/span&gt;
        &lt;span class="na"&gt;currentPage&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;currentPage&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;totalPages&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;totalPages&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;onPageChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handlePageChange&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;

      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;marginTop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;16px&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;fontSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;13px&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#999&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        Page &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;currentPage&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; of &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;totalPages&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  What's happening here?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;generatePosts()&lt;/code&gt; creates 47 fake blog posts — simulating real data from an API.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ITEMS_PER_PAGE = 5&lt;/code&gt; controls how many items appear per page. Change it to 10 or 20 and it just works.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;slice(startIndex, endIndex)&lt;/code&gt; cuts the array to only the current page's data — classic client-side pagination.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;PaginationControls&lt;/code&gt; is a reusable component. Pass it any &lt;code&gt;currentPage&lt;/code&gt;, &lt;code&gt;totalPages&lt;/code&gt;, and &lt;code&gt;onPageChange&lt;/code&gt; — it works with any dataset.&lt;/li&gt;
&lt;li&gt;Prev/Next buttons are disabled at boundaries so users can't go below page 1 or above the last page.&lt;/li&gt;
&lt;li&gt;The active page button highlights with your brand color &lt;code&gt;#fd6e4e&lt;/code&gt;. 🎨&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Best Tips for Pagination
&lt;/h2&gt;

&lt;p&gt;✅ &lt;strong&gt;Always show the user where they are.&lt;/strong&gt; "Page 3 of 12" or "Showing 21–30 of 120 results" gives real context.&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Disable Prev/Next at boundaries.&lt;/strong&gt; Don't let users click into a page that doesn't exist.&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Keep items per page reasonable.&lt;/strong&gt; 10–25 is the sweet spot for most apps. Too few = too many page clicks. Too many = overload.&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Use query params for server-side pagination.&lt;/strong&gt; &lt;code&gt;?page=3&lt;/code&gt; makes pages bookmarkable and shareable.&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Add a loading indicator&lt;/strong&gt; when fetching from an API. Users should know data is on the way.&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Reset to page 1 when filters change.&lt;/strong&gt; If a user is on page 6 and applies a filter that returns only 3 results, jumping back to page 1 automatically prevents confusion.&lt;/p&gt;




&lt;h2&gt;
  
  
  Common Mistakes to Avoid
&lt;/h2&gt;

&lt;p&gt;❌ &lt;strong&gt;Forgetting to reset page on filter/search changes.&lt;/strong&gt; This is the #1 pagination bug. Your users filter by "React" and land on page 8 — which is empty because the filtered result only has 20 items. Always reset &lt;code&gt;currentPage&lt;/code&gt; to 1 when search or filter state changes.&lt;/p&gt;

&lt;p&gt;❌ &lt;strong&gt;Hardcoding item count.&lt;/strong&gt; Avoid &lt;code&gt;Math.ceil(47 / 5)&lt;/code&gt; in your component. Your data length will change. Always compute &lt;code&gt;totalPages&lt;/code&gt; dynamically from the actual data or the API response.&lt;/p&gt;

&lt;p&gt;❌ &lt;strong&gt;Building your own pagination for large datasets.&lt;/strong&gt; Client-side pagination is great for small datasets. For 10,000+ rows, use server-side pagination — always. Slicing a 10,000-item array in the browser is still loading 10,000 items into memory.&lt;/p&gt;

&lt;p&gt;❌ &lt;strong&gt;No "out of bounds" guard.&lt;/strong&gt; What if someone manually types &lt;code&gt;?page=9999&lt;/code&gt; in the URL and your app has only 10 pages? Guard against this. Redirect or clamp to the last valid page.&lt;/p&gt;

&lt;p&gt;❌ &lt;strong&gt;Skipping accessibility.&lt;/strong&gt; Your pagination buttons should have proper &lt;code&gt;aria-label&lt;/code&gt; values and keyboard navigation support. &lt;code&gt;aria-label="Go to page 5"&lt;/code&gt; goes a long way.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Pagination isn't glamorous. Nobody gives awards for a well-paginated list. But it's one of those foundational patterns that quietly makes your apps faster, cheaper to run, and genuinely better to use.&lt;/p&gt;

&lt;p&gt;Once you understand the core idea — &lt;em&gt;split big data into small, navigable chunks&lt;/em&gt; — the rest is just implementation details. Whether you're slicing an array on the frontend, passing &lt;code&gt;LIMIT&lt;/code&gt; and &lt;code&gt;OFFSET&lt;/code&gt; to a SQL query, or using cursor-based pagination for a real-time feed, the goal is always the same: &lt;strong&gt;give the user only what they need, exactly when they need it.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Build the component above, play with &lt;code&gt;ITEMS_PER_PAGE&lt;/code&gt;, and see how the pages shift. That hands-on click is worth more than any explanation.&lt;/p&gt;

&lt;p&gt;For more practical frontend guides like this one, visit 👉 &lt;strong&gt;&lt;a href="https://hamidrazadev.com" rel="noopener noreferrer"&gt;hamidrazadev.com&lt;/a&gt;&lt;/strong&gt; — and if this post saved you from loading 10,000 rows at once, share it with a fellow dev who might need it. 😄&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>typescript</category>
      <category>react</category>
    </item>
    <item>
      <title>pnpm vs npm vs yarn: Which Package Manager Should You Actually Use in 2026?</title>
      <dc:creator>Muhammad Hamid Raza</dc:creator>
      <pubDate>Mon, 27 Apr 2026 09:57:39 +0000</pubDate>
      <link>https://dev.to/hamidrazadev/pnpm-vs-npm-vs-yarn-which-package-manager-should-you-actually-use-3ke3</link>
      <guid>https://dev.to/hamidrazadev/pnpm-vs-npm-vs-yarn-which-package-manager-should-you-actually-use-3ke3</guid>
      <description>&lt;p&gt;You've been there. You clone a new repo, hit &lt;code&gt;npm install&lt;/code&gt;, and watch the cursor blink. And blink. And blink. Meanwhile, your &lt;code&gt;node_modules&lt;/code&gt; folder quietly becomes the heaviest object in the known universe.&lt;/p&gt;

&lt;p&gt;Package managers are one of those tools developers use every single day — yet most of us just pick one and never look back. That's fine, until you're debugging a phantom dependency, waiting forever for CI to finish, or discovering your disk has 40 copies of &lt;code&gt;lodash&lt;/code&gt; sitting around doing nothing useful.&lt;/p&gt;

&lt;p&gt;So which one should you actually use in 2026 — &lt;strong&gt;npm&lt;/strong&gt;, &lt;strong&gt;yarn&lt;/strong&gt;, or &lt;strong&gt;pnpm&lt;/strong&gt;? Let's break it down honestly. 🚀&lt;/p&gt;




&lt;h2&gt;
  
  
  What Is a Package Manager, Anyway?
&lt;/h2&gt;

&lt;p&gt;Think of a package manager like an app store for your code project. Instead of manually downloading and setting up libraries, you just say "I need React" or "I need Lodash" — and the package manager handles everything: downloading, versioning, and organizing.&lt;/p&gt;

&lt;p&gt;When you run &lt;code&gt;npm install express&lt;/code&gt;, you're telling your package manager: &lt;em&gt;"Go find this package, grab the right version, and put it in my project."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;All three tools — npm, yarn, and pnpm — do this job. The difference is &lt;em&gt;how&lt;/em&gt; they do it, and that's where it gets interesting.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Quick Introduction to Each
&lt;/h2&gt;

&lt;h3&gt;
  
  
  npm — The OG
&lt;/h3&gt;

&lt;p&gt;npm (Node Package Manager) has been around since 2009. It comes bundled with Node.js, which means if you have Node installed, you already have npm. No extra setup. No extra thinking.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Current version:&lt;/strong&gt; npm 11.x&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lockfile:&lt;/strong&gt; &lt;code&gt;package-lock.json&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Install command:&lt;/strong&gt; &lt;code&gt;npm install&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;npm powers the largest JavaScript registry in the world — over 2 million packages. That's both its greatest strength and its biggest flex.&lt;/p&gt;

&lt;h3&gt;
  
  
  yarn — The Speed Challenger
&lt;/h3&gt;

&lt;p&gt;Yarn was created by Facebook in 2016 specifically to fix npm's pain points at the time: slow installs, unreliable dependency resolution, and no lockfile. It shipped fast, it shipped with &lt;code&gt;yarn.lock&lt;/code&gt;, and developers loved it.&lt;/p&gt;

&lt;p&gt;Today there are two very different versions of Yarn:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Yarn Classic (v1):&lt;/strong&gt; The original. Entered maintenance mode in 2020. Still used in many projects, but no longer actively developed.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Yarn Berry (v2, v3, v4):&lt;/strong&gt; A complete rewrite. Introduces Plug'n'Play (PnP), which gets rid of &lt;code&gt;node_modules&lt;/code&gt; entirely. Powerful, but also divisive.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Current version:&lt;/strong&gt; Yarn 4.x (Berry)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lockfile:&lt;/strong&gt; &lt;code&gt;yarn.lock&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Install command:&lt;/strong&gt; &lt;code&gt;yarn install&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  pnpm — The Efficient One
&lt;/h3&gt;

&lt;p&gt;pnpm (Performant npm) launched in 2017 and took a completely different approach to storing packages. Instead of copying every dependency into each project's &lt;code&gt;node_modules&lt;/code&gt;, pnpm stores packages once in a global content-addressable store and uses hard links.&lt;/p&gt;

&lt;p&gt;The result? Blazing fast installs and massively less disk usage.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Current version:&lt;/strong&gt; pnpm 10.x (pnpm 11 RC just landed in April 2026)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lockfile:&lt;/strong&gt; &lt;code&gt;pnpm-lock.yaml&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Install command:&lt;/strong&gt; &lt;code&gt;pnpm install&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Why Does It Actually Matter?
&lt;/h2&gt;

&lt;p&gt;You might be thinking: &lt;em&gt;"They all install packages. Who cares?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Here's why you should care:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Your CI/CD pipeline&lt;/strong&gt; runs &lt;code&gt;npm install&lt;/code&gt; on every push. If that takes 3 minutes with npm but 45 seconds with pnpm, you're wasting real time and real money every single day.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Your disk space&lt;/strong&gt; is getting eaten by duplicate copies of the same packages across 10 different projects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Your team&lt;/strong&gt; might be hitting phantom dependency bugs — using packages that aren't in &lt;code&gt;package.json&lt;/code&gt; but happen to be installed anyway.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security&lt;/strong&gt; is a real concern in 2026. Package supply chain attacks are happening, and your package manager is the first line of defense.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These aren't abstract problems. They affect your daily workflow.&lt;/p&gt;




&lt;h2&gt;
  
  
  Benefits and Real-World Examples
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ✅ npm — Simplicity Wins Sometimes
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zero setup required.&lt;/strong&gt; Start a new Node project, and npm is already there. Perfect for beginners and solo projects where you don't want to think about tooling.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Maximum compatibility.&lt;/strong&gt; Every npm package, every tutorial, every CI/CD template assumes you're using npm. Nothing breaks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Workspaces support.&lt;/strong&gt; npm v7+ added workspaces, so monorepos are supported. It's not as powerful as the alternatives, but it works.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Real example:&lt;/strong&gt; You're building a quick prototype for a client demo. You fire up &lt;code&gt;npm init&lt;/code&gt; and start coding in minutes. No extra installation. No configuration. Just works.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ yarn — When PnP Makes Sense
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zero-installs.&lt;/strong&gt; Yarn Berry's biggest trick: commit your dependency cache to Git. Your team or CI server never runs &lt;code&gt;yarn install&lt;/code&gt; again — everything is already there.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Plugin architecture.&lt;/strong&gt; Yarn Berry has a modular plugin system, and as of the latest v4 releases, official plugins are now bundled by default, so you don't need to run &lt;code&gt;yarn plugin import&lt;/code&gt; for official ones anymore.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Portable shell scripts.&lt;/strong&gt; Yarn uses a bash-compatible shell to make &lt;code&gt;package.json&lt;/code&gt; scripts run consistently across Windows, Linux, and macOS.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Real example:&lt;/strong&gt; A team commits their Yarn cache to Git. New developers join, clone the repo, and immediately run the app without installing anything. CI becomes near-instant.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ pnpm — Efficiency at Scale
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Disk space savings.&lt;/strong&gt; pnpm's content-addressable global store means if 10 of your projects use React 19, there's only &lt;strong&gt;one copy&lt;/strong&gt; of React 19 on your disk. This can save 70–80% of disk space compared to npm.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Strict dependency isolation.&lt;/strong&gt; pnpm prevents phantom dependencies at the filesystem level. A package can only access what's listed in its own &lt;code&gt;package.json&lt;/code&gt;. npm and yarn don't enforce this.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Blazing fast installs.&lt;/strong&gt; pnpm consistently outperforms npm in benchmarks, especially for cached installs and monorepo setups.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security by default (v10+).&lt;/strong&gt; pnpm v10 introduced a game-changing security model: lifecycle scripts (&lt;code&gt;postinstall&lt;/code&gt;, &lt;code&gt;preinstall&lt;/code&gt;) are no longer run by default — a huge reduction in supply chain attack risk. The new &lt;code&gt;minimumReleaseAge&lt;/code&gt; setting (defaulting to 1 day in v11) blocks newly published packages for 24 hours, giving the community time to spot compromised versions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monorepo powerhouse.&lt;/strong&gt; Commands like &lt;code&gt;pnpm --filter&lt;/code&gt; and &lt;code&gt;pnpm -r&lt;/code&gt; (recursive) make working with multi-package repos clean and fast.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Real example:&lt;/strong&gt; You manage 15 React projects on your machine. With npm, you have 15 separate copies of React sitting on disk. With pnpm, you have one — hard-linked to all 15 projects. Your disk breathes again. 😊&lt;/p&gt;




&lt;h2&gt;
  
  
  Head-to-Head Comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;npm&lt;/th&gt;
&lt;th&gt;yarn (Berry)&lt;/th&gt;
&lt;th&gt;pnpm&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Comes with Node.js&lt;/td&gt;
&lt;td&gt;✅ Yes&lt;/td&gt;
&lt;td&gt;❌ Install separately&lt;/td&gt;
&lt;td&gt;❌ Install separately&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Speed (cold install)&lt;/td&gt;
&lt;td&gt;🐢 Slowest&lt;/td&gt;
&lt;td&gt;⚡ Fast (PnP mode)&lt;/td&gt;
&lt;td&gt;⚡ Fast&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Speed (cached)&lt;/td&gt;
&lt;td&gt;🐢 Slower&lt;/td&gt;
&lt;td&gt;⚡ Very fast&lt;/td&gt;
&lt;td&gt;⚡ Very fast&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Disk efficiency&lt;/td&gt;
&lt;td&gt;❌ Many copies&lt;/td&gt;
&lt;td&gt;✅ Good (PnP/ZIP)&lt;/td&gt;
&lt;td&gt;✅ Best (global store)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Monorepo support&lt;/td&gt;
&lt;td&gt;⚠️ Basic&lt;/td&gt;
&lt;td&gt;✅ Strong&lt;/td&gt;
&lt;td&gt;✅ Excellent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Phantom dependencies&lt;/td&gt;
&lt;td&gt;❌ Allowed&lt;/td&gt;
&lt;td&gt;⚠️ Depends on mode&lt;/td&gt;
&lt;td&gt;✅ Prevented&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Security defaults&lt;/td&gt;
&lt;td&gt;⚠️ Standard&lt;/td&gt;
&lt;td&gt;⚠️ Standard&lt;/td&gt;
&lt;td&gt;✅ Strictest (v10+)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Learning curve&lt;/td&gt;
&lt;td&gt;✅ Lowest&lt;/td&gt;
&lt;td&gt;❌ High (Berry/PnP)&lt;/td&gt;
&lt;td&gt;✅ Low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ecosystem compatibility&lt;/td&gt;
&lt;td&gt;✅ Maximum&lt;/td&gt;
&lt;td&gt;⚠️ PnP can break things&lt;/td&gt;
&lt;td&gt;✅ High&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lockfile&lt;/td&gt;
&lt;td&gt;&lt;code&gt;package-lock.json&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;yarn.lock&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pnpm-lock.yaml&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Best Tips: Do's and Don'ts
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Do's ✅
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Do use &lt;code&gt;pnpm&lt;/code&gt; for any new project where you care about speed and disk efficiency.&lt;/strong&gt; The learning curve is minimal — most commands are identical to npm.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Do use npm if you're teaching beginners.&lt;/strong&gt; The zero-configuration setup removes unnecessary friction.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Do use Yarn Berry if your team is already invested in PnP and zero-installs.&lt;/strong&gt; If your whole toolchain supports it, the workflow is genuinely fast.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Do commit a lockfile in every project&lt;/strong&gt;, no matter which manager you use. This ensures consistent installs across your team and CI.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Do stick to one package manager per project.&lt;/strong&gt; Mixing npm and pnpm in the same repo causes weird issues. Use the &lt;code&gt;packageManager&lt;/code&gt; field in &lt;code&gt;package.json&lt;/code&gt; to enforce this.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Don'ts ❌
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Don't use Yarn Classic (v1) for new projects.&lt;/strong&gt; It's been in maintenance mode since 2020 and only gets security fixes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don't &lt;code&gt;npm install&lt;/code&gt; and &lt;code&gt;pnpm install&lt;/code&gt; in the same repo.&lt;/strong&gt; You'll get two different lockfiles, two different &lt;code&gt;node_modules&lt;/code&gt; structures, and one very confused team.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don't delete &lt;code&gt;node_modules&lt;/code&gt; and reinstall as your first debug step every time.&lt;/strong&gt; Learn what your lockfile is telling you first.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don't ignore security defaults.&lt;/strong&gt; If you're on pnpm v10+, the &lt;code&gt;allowBuilds&lt;/code&gt; setting matters. Take a few minutes to understand which packages need build scripts.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Common Mistakes Developers Make
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Treating all three as identical
&lt;/h3&gt;

&lt;p&gt;They're not. pnpm's &lt;code&gt;node_modules&lt;/code&gt; structure looks different from npm's, because it uses symlinks. Some poorly written packages that access the filesystem directly might behave unexpectedly. Always test when switching.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Mixing package managers in a monorepo
&lt;/h3&gt;

&lt;p&gt;This is more common than you'd think. One developer uses yarn, another uses npm — and suddenly the lockfile is a mess and installs are inconsistent. Add a &lt;code&gt;packageManager&lt;/code&gt; field to your root &lt;code&gt;package.json&lt;/code&gt; and use Corepack to enforce it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"packageManager"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"pnpm@10.33.0"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Jumping straight to Yarn Berry without checking PnP compatibility
&lt;/h3&gt;

&lt;p&gt;Yarn PnP is powerful, but it changes how Node resolves modules. Some tools — older Jest configs, certain Webpack plugins, some IDE extensions — need extra setup to work properly. Don't assume it'll "just work."&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Never updating the package manager itself
&lt;/h3&gt;

&lt;p&gt;You probably update your dependencies regularly. But when's the last time you updated npm, yarn, or pnpm? pnpm v10 alone shipped massive security improvements over v9. Keep your tools updated too.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Update npm&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; npm@latest

&lt;span class="c"&gt;# Update yarn&lt;/span&gt;
yarn &lt;span class="nb"&gt;set &lt;/span&gt;version stable

&lt;span class="c"&gt;# Update pnpm&lt;/span&gt;
pnpm self-update
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. Ignoring the lockfile in &lt;code&gt;.gitignore&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Your lockfile is not optional. It's what ensures reproducible installs. If you see &lt;code&gt;package-lock.json&lt;/code&gt; or &lt;code&gt;pnpm-lock.yaml&lt;/code&gt; in your &lt;code&gt;.gitignore&lt;/code&gt;, that's a problem — commit it.&lt;/p&gt;




&lt;h2&gt;
  
  
  So, Which One Should You Actually Use?
&lt;/h2&gt;

&lt;p&gt;Here's the honest, no-fluff answer:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use npm if:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You're a beginner just getting started with Node.js&lt;/li&gt;
&lt;li&gt;You're building a simple project where speed and disk usage aren't a concern&lt;/li&gt;
&lt;li&gt;You want maximum compatibility with every tutorial and tool out there&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Use yarn (Berry) if:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your team is already using it and you have PnP working well&lt;/li&gt;
&lt;li&gt;You want zero-installs for a CI/CD speed boost&lt;/li&gt;
&lt;li&gt;You're working on a monorepo and your toolchain fully supports PnP&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Use pnpm if:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You're starting a new project and want the best balance of speed, disk efficiency, and compatibility&lt;/li&gt;
&lt;li&gt;You're working on a monorepo with multiple packages&lt;/li&gt;
&lt;li&gt;You care about security and want stricter dependency isolation out of the box&lt;/li&gt;
&lt;li&gt;You manage many projects on the same machine and your disk is screaming&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For most developers reading this in 2026, &lt;strong&gt;pnpm is the practical upgrade&lt;/strong&gt; — it's fast, it's efficient, its commands are nearly identical to npm, and pnpm v10's security-first approach is genuinely impressive. You won't regret it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;The package manager debate isn't about picking the "coolest" tool. It's about understanding what each tool actually does, and choosing the right one for your situation.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;npm&lt;/strong&gt; is reliable, universally supported, and perfect for getting started&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;yarn&lt;/strong&gt; brought speed and innovation to the ecosystem, and Yarn Berry continues to push boundaries&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;pnpm&lt;/strong&gt; delivers the best combination of speed, disk efficiency, and modern security defaults for production use&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you haven't tried pnpm yet, it takes about 5 minutes to switch and a single command to install:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; pnpm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Give it a week. You might not go back. 💡&lt;/p&gt;




&lt;p&gt;Want more hands-on dev content like this? Head over to &lt;strong&gt;&lt;a href="https://hamidrazadev.com" rel="noopener noreferrer"&gt;hamidrazadev.com&lt;/a&gt;&lt;/strong&gt; — there's a lot more where this came from. If this article saved you some confusion (or some disk space), share it with a fellow developer who's still on the npm default. They'll thank you later. 🔧&lt;/p&gt;

</description>
      <category>node</category>
      <category>webdev</category>
      <category>discuss</category>
      <category>performance</category>
    </item>
  </channel>
</rss>
