<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[geodask]]></title><description><![CDATA[geodask]]></description><link>https://blog.geodask.com</link><generator>RSS for Node</generator><lastBuildDate>Fri, 10 Apr 2026 08:02:02 GMT</lastBuildDate><atom:link href="https://blog.geodask.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[A Beginner's Guide to Reusable Type-Safe Components in Svelte 5]]></title><description><![CDATA[Introduction
Generics are an incredibly useful feature in TypeScript that let you build components with APIs that are both reusable and safe. Think of them as a way to create functions, classes, or Svelte components that work with various types inste...]]></description><link>https://blog.geodask.com/a-beginners-guide-to-reusable-type-safe-components-in-svelte-5</link><guid isPermaLink="true">https://blog.geodask.com/a-beginners-guide-to-reusable-type-safe-components-in-svelte-5</guid><category><![CDATA[Frontend Development]]></category><category><![CDATA[Svelte]]></category><category><![CDATA[Sveltekit]]></category><category><![CDATA[TypeScript]]></category><dc:creator><![CDATA[George Daskalakis]]></dc:creator><pubDate>Tue, 24 Dec 2024 17:48:38 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1743492535052/070dde79-4d14-4591-b193-58c9b7b20943.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>Generics are an incredibly useful feature in TypeScript that let you build components with APIs that are both reusable and safe. Think of them as a way to create functions, classes, or Svelte components that work with various types instead of being locked into one. This means your components can adapt to different types without losing their type-checking powers—pretty handy when you're dealing with collections of data or custom callbacks.</p>
<p>In this article, we'll dive into how you can use generics in Svelte 5 to create reusable components that feel like a dream to use. We’ll also sprinkle in snippets—a feature that complements generics by giving you more control over how things are displayed. By the end, you’ll have a better idea of how these tools make your code cleaner, easier to maintain, and a joy to work with.</p>
<p>Generics and snippets are perfect for developers who want to make their components more versatile without sacrificing readability or safety. As your projects grow, these tools can help you avoid duplicating code while maintaining a clear structure in your codebase. Let’s start by understanding the basics of generics and how they fit into Svelte development.</p>
<h2 id="heading-getting-started-with-generics">Getting Started with Generics</h2>
<p>Generics are like placeholders for types that get replaced when the function or component is used. Here’s a quick example to get the idea across:</p>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getFirst</span>&lt;<span class="hljs-title">T</span>&gt;(<span class="hljs-params">arr: T[]</span>): <span class="hljs-title">T</span> </span>{
  <span class="hljs-keyword">return</span> arr[<span class="hljs-number">0</span>];
}

<span class="hljs-keyword">const</span> firstNumber = getFirst([<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>]); <span class="hljs-comment">// TypeScript figures out T is a number</span>
<span class="hljs-keyword">const</span> firstString = getFirst([<span class="hljs-string">'Alice'</span>, <span class="hljs-string">'Bob'</span>]); <span class="hljs-comment">// Here, T becomes a string</span>
</code></pre>
<p>Notice how the type of <code>T</code> is inferred based on the array you pass in? This keeps things both flexible and safe. You can apply the same concept to Svelte components to make them adaptable to whatever data they need to handle.</p>
<p>Generics are especially handy for scenarios where you’re building utility functions or components that work with multiple data types. They allow you to avoid repetitive code while maintaining strong type guarantees. Let’s see how this concept applies to Svelte components, where generics can bring additional flexibility to UI development.</p>
<h2 id="heading-generics-in-svelte-components">Generics in Svelte Components</h2>
<p>In Svelte 5, generics are easy to use with the <code>generics</code> attribute in your <code>&lt;script&gt;</code> tag. Let’s take a look at a simple <code>List</code> component that can display any type of item:</p>
<pre><code class="lang-svelte"><span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"ts"</span> <span class="hljs-attr">generics</span>=<span class="hljs-string">"T"</span>&gt;</span><span class="javascript">
  <span class="hljs-keyword">let</span> </span></span><span class="javascript">{ items }</span><span class="xml">: </span><span class="javascript">{ <span class="hljs-attr">items</span>: T[] }</span><span class="xml"> = $props();
<span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
  </span><span class="javascript">{</span><span class="hljs-keyword">#each</span><span class="javascript"> items <span class="hljs-keyword">as</span> item}</span><span class="xml">
    <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span></span><span class="javascript">{item}</span><span class="xml"><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
  </span><span class="javascript">{</span><span class="hljs-keyword">/each</span><span class="javascript">}</span><span class="xml">
<span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span></span>
</code></pre>
<p>Here, the <code>items</code> prop is flexible and adapts to whatever type the parent component specifies. This makes the <code>List</code> component incredibly reusable. You don’t need to write separate components for numbers, strings, or objects—just let the parent decide.</p>
<p>The real beauty of this approach is that it scales effortlessly. Whether you’re displaying a list of strings, numbers, or complex objects, the component remains the same. Plus, you get the added bonus of TypeScript’s type-checking to catch potential bugs during development.</p>
<h3 id="heading-example-1-displaying-strings">Example 1: Displaying Strings</h3>
<pre><code class="lang-svelte"><span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"ts"</span>&gt;</span><span class="javascript">
  <span class="hljs-keyword">import</span> List <span class="hljs-keyword">from</span> <span class="hljs-string">'./List.svelte'</span>;

  <span class="hljs-keyword">let</span> names = [<span class="hljs-string">'Alice'</span>, <span class="hljs-string">'Bob'</span>, <span class="hljs-string">'Charlie'</span>];
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">List</span> <span class="hljs-attr">items</span>=</span></span><span class="javascript">{names}</span><span class="xml"><span class="hljs-tag"> /&gt;</span></span>
</code></pre>
<h3 id="heading-example-2-displaying-numbers">Example 2: Displaying Numbers</h3>
<pre><code class="lang-svelte"><span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"ts"</span>&gt;</span><span class="javascript">
  <span class="hljs-keyword">import</span> List <span class="hljs-keyword">from</span> <span class="hljs-string">'./List.svelte'</span>;

  <span class="hljs-keyword">let</span> numbers = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>];
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">List</span> <span class="hljs-attr">items</span>=</span></span><span class="javascript">{numbers}</span><span class="xml"><span class="hljs-tag"> /&gt;</span></span>
</code></pre>
<p>Generics make this process seamless. You get type safety and flexibility without writing repetitive code. Plus, TypeScript gives you immediate feedback if something doesn’t line up, which means fewer bugs and more confidence in your code.</p>
<p>Another advantage of using generics is that they make your components future-proof. As your application evolves, you can easily adapt these components to handle new data types without rewriting them. This saves time and ensures consistency across your project.</p>
<h2 id="heading-making-components-interactive-with-callbacks">Making Components Interactive with Callbacks</h2>
<p>Generics show their true power when paired with callbacks. Using them alone provides type safety, but the real value comes when your components start interacting with data. Here’s an example of a <code>List</code> component that lets you handle item clicks:</p>
<pre><code class="lang-svelte"><span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"ts"</span> <span class="hljs-attr">generics</span>=<span class="hljs-string">"T"</span>&gt;</span><span class="javascript">
  <span class="hljs-keyword">let</span> </span></span><span class="javascript">{ items, onSelect }</span><span class="xml">: </span><span class="javascript">{ <span class="hljs-attr">items</span>: T[]; onSelect: <span class="hljs-function">(<span class="hljs-params">item: T</span>) =&gt;</span> <span class="hljs-keyword">void</span> }</span><span class="xml"> = $props();
<span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
  </span><span class="javascript">{</span><span class="hljs-keyword">#each</span><span class="javascript"> items <span class="hljs-keyword">as</span> item}</span><span class="xml">
    <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">onclick</span>=</span></span><span class="javascript">{<span class="hljs-function">() =&gt;</span> onSelect(item)}</span><span class="xml"><span class="hljs-tag">&gt;</span></span><span class="javascript">{item}</span><span class="xml"><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
  </span><span class="javascript">{</span><span class="hljs-keyword">/each</span><span class="javascript">}</span><span class="xml">
<span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span></span>
</code></pre>
<p>With this setup, the parent component controls what happens when an item is clicked, and TypeScript ensures that the <code>onSelect</code> function gets the right type of item.</p>
<h3 id="heading-example-3-handling-user-objects">Example 3: Handling User Objects</h3>
<pre><code class="lang-svelte"><span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"ts"</span>&gt;</span><span class="javascript">
  <span class="hljs-keyword">import</span> List <span class="hljs-keyword">from</span> <span class="hljs-string">'./List.svelte'</span>;

  type User = </span></span><span class="javascript">{ <span class="hljs-attr">id</span>: number; name: string }</span><span class="xml"><span class="javascript">;
  <span class="hljs-keyword">let</span> users: User[] = [
    </span></span><span class="javascript">{ <span class="hljs-attr">id</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">name</span>: <span class="hljs-string">'Alice'</span> }</span><span class="xml">,
    </span><span class="javascript">{ <span class="hljs-attr">id</span>: <span class="hljs-number">2</span>, <span class="hljs-attr">name</span>: <span class="hljs-string">'Bob'</span> }</span><span class="xml"><span class="javascript">
  ];

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleSelect</span>(<span class="hljs-params">user: User</span>) </span></span></span><span class="javascript">{
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Selected user:'</span>, user.name);
  }</span><span class="xml">
<span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">List</span> <span class="hljs-attr">items</span>=</span></span><span class="javascript">{users}</span><span class="xml"><span class="hljs-tag"> <span class="hljs-attr">onSelect</span>=</span></span><span class="javascript">{handleSelect}</span><span class="xml"><span class="hljs-tag"> /&gt;</span></span>
</code></pre>
<p>This approach keeps things clean and ensures that your interactions are consistent with the data type you’re working with. Whether it’s a <code>User</code> object or something else entirely, TypeScript has your back.</p>
<p>Interactive components like this are invaluable for building dynamic interfaces. You can use the same pattern for forms, dashboards, or e-commerce applications where user interaction is key.</p>
<h2 id="heading-adding-flexibility-with-snippets">Adding Flexibility with Snippets</h2>
<p>Generics are great for handling data, but what if you want to customize how each item looks? That’s where snippets come in. They let you define how items should be rendered, giving the parent component full control over presentation.</p>
<p>Snippets are like templates that you can pass to a child component. They make it easy to tailor the appearance of your data without modifying the component itself. This is especially useful when working with complex UIs that need to display the same data in different ways.</p>
<h3 id="heading-updating-the-list-component">Updating the <code>List</code> Component</h3>
<pre><code class="lang-svelte"><span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"ts"</span> <span class="hljs-attr">generics</span>=<span class="hljs-string">"T"</span>&gt;</span><span class="javascript">
  <span class="hljs-keyword">import</span> </span></span><span class="javascript">{ Snippet }</span><span class="xml"><span class="javascript"> <span class="hljs-keyword">from</span> <span class="hljs-string">'svelte'</span>;

  type ListProps&lt;T&gt; = </span></span><span class="javascript">{
    <span class="hljs-attr">items</span>: T[];
    itemTemplate?: Snippet&lt;[T]&gt;;
  }</span><span class="xml"><span class="javascript">;

  <span class="hljs-keyword">let</span> </span></span><span class="javascript">{ items, itemTemplate }</span><span class="xml"><span class="xml">: ListProps<span class="hljs-tag">&lt;<span class="hljs-name">T</span>&gt;</span> = $props();
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
  </span><span class="javascript">{</span><span class="hljs-keyword">#each</span><span class="javascript"> items <span class="hljs-keyword">as</span> item}</span><span class="xml">
    <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
      </span><span class="javascript">{</span><span class="hljs-keyword">#if</span><span class="javascript"> itemTemplate}</span><span class="xml">
        </span><span class="javascript">{@render itemTemplate(item)}</span><span class="xml">
      </span><span class="javascript">{</span><span class="hljs-keyword">:else</span><span class="javascript">}</span><span class="xml">
        </span><span class="javascript">{item}</span><span class="xml">
      </span><span class="javascript">{</span><span class="hljs-keyword">/if</span><span class="javascript">}</span><span class="xml">
    <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
  </span><span class="javascript">{</span><span class="hljs-keyword">/each</span><span class="javascript">}</span><span class="xml">
<span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span></span>
</code></pre>
<h3 id="heading-example-4-customizing-the-display">Example 4: Customizing the Display</h3>
<pre><code class="lang-svelte"><span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"ts"</span>&gt;</span><span class="javascript">
  <span class="hljs-keyword">import</span> List <span class="hljs-keyword">from</span> <span class="hljs-string">'./List.svelte'</span>;

  type User = </span></span><span class="javascript">{ <span class="hljs-attr">id</span>: number; name: string }</span><span class="xml"><span class="javascript">;
  <span class="hljs-keyword">let</span> users: User[] = [
    </span></span><span class="javascript">{ <span class="hljs-attr">id</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">name</span>: <span class="hljs-string">'Alice'</span> }</span><span class="xml">,
    </span><span class="javascript">{ <span class="hljs-attr">id</span>: <span class="hljs-number">2</span>, <span class="hljs-attr">name</span>: <span class="hljs-string">'Bob'</span> }</span><span class="xml">
  ];
<span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">List</span> <span class="hljs-attr">items</span>=</span></span><span class="javascript">{users}</span><span class="xml"><span class="hljs-tag">&gt;</span>
  </span><span class="javascript">{#snippet itemTemplate(user: User)}</span><span class="xml">
    <span class="hljs-tag">&lt;<span class="hljs-name">strong</span>&gt;</span></span><span class="javascript">{user.name}</span><span class="xml"><span class="hljs-tag">&lt;/<span class="hljs-name">strong</span>&gt;</span> (ID: </span><span class="javascript">{user.id}</span><span class="xml">)
  </span><span class="javascript">{/snippet}</span><span class="xml">
<span class="hljs-tag">&lt;/<span class="hljs-name">List</span>&gt;</span></span>
</code></pre>
<p>This gives you the best of both worlds: reusable components and fully customizable rendering. It’s especially useful when you’re working on complex applications where different contexts might need different visual treatments.</p>
<h2 id="heading-wrapping-it-up">Wrapping It Up</h2>
<p>Generics and snippets in Svelte 5 are a game-changer for building flexible, type-safe components. Generics let your components adapt to different types of data while maintaining strict type checking. Snippets, on the other hand, let you customize how your components look without sacrificing reusability.</p>
<p>Whether you’re building a simple list or a complex UI, these tools make your job easier and your code cleaner. Start using generics and snippets today, and see how they can transform your workflow!</p>
<p>These techniques aren’t just for advanced users. Even if you’re new to Svelte or TypeScript, mastering generics and snippets can greatly enhance your productivity. So why wait? Dive in and make your components smarter, more adaptable, and more fun to work with!</p>
<p>Cover photo by: <a target="_blank" href="https://storyset.com/online">Online illustrations by Storyset</a></p>
]]></content:encoded></item><item><title><![CDATA[Semantic Differences and Structural Similarities]]></title><description><![CDATA[In modern front-end development, we strive to create reusable components to save time and reduce duplication. But if we prioritize reusability too much, we risk sacrificing clarity and flexibility. A common pitfall is to build overly generic componen...]]></description><link>https://blog.geodask.com/semantic-differences-structural-similarities</link><guid isPermaLink="true">https://blog.geodask.com/semantic-differences-structural-similarities</guid><category><![CDATA[Frontend Development]]></category><category><![CDATA[frontend]]></category><category><![CDATA[Programming Tips]]></category><category><![CDATA[development]]></category><category><![CDATA[Developer]]></category><dc:creator><![CDATA[George Daskalakis]]></dc:creator><pubDate>Tue, 19 Nov 2024 16:43:09 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1732619546949/2b29d882-9d74-4eed-b7a0-2240b6be3ddf.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In modern front-end development, we strive to create reusable components to save time and reduce duplication. But if we prioritize reusability too much, we risk sacrificing clarity and flexibility. A common pitfall is to build overly generic components that blur the semantic distinctions between different UI elements, leading to a more complex and harder-to-maintain codebase.</p>
<p>In this article, I’ll walk you through my approach to structuring components by prioritizing <strong>ontological meaning</strong>—what a component <strong>represents</strong> in your application—its purpose or role—rather than how it looks, and how this can help avoid common pitfalls when building complex UIs.</p>
<p><em>Ontological meaning refers to the purpose or concept a component represents within your application. While components may look similar, their meaning—or ontology—can be different. For example, a TaskCard and ProjectCard might both display a title and a progress bar, but they represent two very different concepts.</em></p>
<h2 id="heading-the-naive-approach-one-generic-component-for-everything">The Naive Approach: One Generic Component for Everything</h2>
<p>When you're building a front-end application, you’ll often come across components that look similar at first glance. Imagine a Project Card and a Task Card. Both cards might show a title, a description, and a progress bar, but they represent fundamentally different concepts: a project and a task.</p>
<p>A <strong>naive approach</strong> might suggest: “These two cards look the same, so let’s just create one generic component that can handle both!”</p>
<p>You could end up with something like this:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Generic InfoCard component</span>
<span class="hljs-keyword">const</span> InfoCard = <span class="hljs-function">(<span class="hljs-params">{ title, description, progress }</span>) =&gt;</span> (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"info-card"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>{title}<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{description}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"progress-bar"</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">width:</span> `${<span class="hljs-attr">progress</span>}%` }} /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
);
</code></pre>
<p>Instead of creating separate components for <code>ProjectCard</code> and <code>TaskCard</code>, you would simply pass different data into this single generic InfoCard component:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Using InfoCard for a Project</span>
&lt;InfoCard title=<span class="hljs-string">"Website Redesign"</span> description=<span class="hljs-string">"Redesigning the homepage with a new layout"</span> progress={<span class="hljs-number">40</span>} /&gt;

<span class="hljs-comment">// Using InfoCard for a Task</span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">InfoCard</span> <span class="hljs-attr">title</span>=<span class="hljs-string">"Create Wireframe"</span> <span class="hljs-attr">description</span>=<span class="hljs-string">"Design the initial wireframe for the homepage layout"</span> <span class="hljs-attr">progress</span>=<span class="hljs-string">{60}</span> /&gt;</span></span>
</code></pre>
<p>At first glance, this might seem like a time-saving strategy. After all, both components share the same structure, so why not create a single generic component? However, this desire for efficiency can introduce long-term challenges.</p>
<h3 id="heading-the-problems-with-a-single-generic-component">The Problems with a Single Generic Component</h3>
<ol>
<li><p><strong>Loss of Semantic Meaning:</strong> By using the same <code>InfoCard</code> for both projects and tasks, you start to lose the <strong>ontological meaning</strong> of these components. Is this component about a project or a task? Over time, it’s easy to forget the distinction. While the <code>InfoCard</code> looks the same, it represents two different things.</p>
</li>
<li><p><strong>Lack of Flexibility:</strong> What happens when one of these cards needs to change? Let’s say you need to add task assignees or due dates to the <code>TaskCard</code>. Now, you have to modify the <code>InfoCard</code> to accommodate these new features. The problem is, this generic component might also be used for projects, which don’t need the same updates. You end up adding conditional logic and props to handle edge cases, cluttering your shared component with unnecessary complexity.</p>
</li>
<li><p><strong>Harder to Maintain:</strong> As the generic <code>InfoCard</code> becomes more complex, it becomes harder to maintain. You might start introducing props like <code>isProject</code> or <code>isTask</code>, which increase the mental load for anyone maintaining the component making it harder to understand and debug. Over time, this kind of complexity leads to "prop bloat," where the component accepts more and more parameters to handle different scenarios.</p>
</li>
</ol>
<h2 id="heading-a-better-approach-semantic-components-with-shared-structure">A Better Approach: Semantic Components with Shared Structure</h2>
<p>Instead of trying to force unrelated concepts into a single generic component, it's better to think of components as <strong>semantically different</strong> but <strong>structurally similar</strong>. This means you should create separate components for <code>ProjectCard</code> and <code>TaskCard</code> even if they share the same layout at the start. You can still share the structure (like the card layout) between them, but by keeping their identity distinct, you give yourself much more flexibility for the future.</p>
<p>Here’s how it could look:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> InfoCard = <span class="hljs-function">(<span class="hljs-params">{ title, description, progress }</span>) =&gt;</span> (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"info-card"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>{title}<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{description}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"progress-bar"</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">width:</span> `${<span class="hljs-attr">progress</span>}%` }} /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
);
</code></pre>
<pre><code class="lang-javascript"><span class="hljs-comment">// ProjectCard.js - Semantically distinct component</span>
<span class="hljs-keyword">const</span> ProjectCard = <span class="hljs-function">(<span class="hljs-params">{ projectName, projectDescription, projectProgress }</span>) =&gt;</span> (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">InfoCard</span> <span class="hljs-attr">title</span>=<span class="hljs-string">{projectName}</span> <span class="hljs-attr">description</span>=<span class="hljs-string">{projectDescription}</span> <span class="hljs-attr">progress</span>=<span class="hljs-string">{projectProgress}</span> /&gt;</span></span>
);

<span class="hljs-comment">// TaskCard.js - Semantically distinct component</span>
<span class="hljs-keyword">const</span> TaskCard = <span class="hljs-function">(<span class="hljs-params">{ taskName, taskDescription, taskProgress }</span>) =&gt;</span> (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">InfoCard</span> <span class="hljs-attr">title</span>=<span class="hljs-string">{taskName}</span> <span class="hljs-attr">description</span>=<span class="hljs-string">{taskDescription}</span> <span class="hljs-attr">progress</span>=<span class="hljs-string">{taskProgress}</span> /&gt;</span></span>
);
</code></pre>
<p>At first glance, this might look like unnecessary boilerplate since both <code>ProjectCard</code> and <code>TaskCard</code> are essentially just wrapping the same <code>InfoCard</code>. But this boilerplate is intentional and provides several key benefits.</p>
<h3 id="heading-why-boilerplate-isnt-always-bad">Why Boilerplate Isn’t Always Bad</h3>
<ol>
<li><p><strong>Clarity</strong>: By having distinct <code>ProjectCard</code> and <code>TaskCard</code> components, you maintain a clear separation of meaning. If someone new joins your team, they will immediately understand that <code>ProjectCard</code> deals with a project and <code>TaskCard</code> deals with a task, even if they share the same structure. This makes your code easier to understand and maintain over time.</p>
</li>
<li><p><strong>Flexibility</strong>: As your application evolves, <code>ProjectCard</code> and <code>TaskCard</code> can evolve independently to meet new requirements. For example, let's say you want to add additional information to the <code>ProjectCard</code>, such as project deadlines or milestones. Instead of modifying a shared component like <code>InfoCard</code>, you can extend or replace the entire structure of the <code>ProjectCard</code> while keeping the <code>TaskCard</code> untouched.</p>
</li>
</ol>
<p>For instance, if you want to add more detailed project information to the <code>ProjectCard</code>, you can simply replace <code>InfoCard</code> with a more complex component:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> ProjectCard = <span class="hljs-function">(<span class="hljs-params">{ projectName, projectDescription, projectProgress, projectDeadline }</span>) =&gt;</span> (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">ExtendedProjectInfoCard</span> 
      <span class="hljs-attr">title</span>=<span class="hljs-string">{projectName}</span> 
      <span class="hljs-attr">description</span>=<span class="hljs-string">{projectDescription}</span> 
      <span class="hljs-attr">progress</span>=<span class="hljs-string">{projectProgress}</span> 
      <span class="hljs-attr">deadline</span>=<span class="hljs-string">{projectDeadline}</span> 
    /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
);
</code></pre>
<ol start="3">
<li><strong>Maintainability</strong>: It makes your code easier to maintain in the long run by keeping components focused and modular. When you need to make changes, you know exactly where to look, and you can be confident that updates to one component won’t inadvertently affect another. You avoid unecessary conditional logic and props that clutter your shared components.</li>
</ol>
<h3 id="heading-balancing-reusability-and-flexibility">Balancing Reusability and Flexibility</h3>
<p>The key here is to <strong>reuse what makes sense</strong> but not force reuse at the expense of <strong>clarity</strong> or <strong>flexibility</strong>. Reusing the shared structure (like <code>InfoCard</code>) helps maintain consistency and reduces duplication, but by keeping <code>ProjectCard</code> and <code>TaskCard</code> semantically distinct, you allow each component to evolve independently. This leads to a <strong>cleaner codebase</strong>, more <strong>scalable components</strong>, and less <strong>brittle logic</strong>.</p>
<h2 id="heading-conclusion-prioritize-semantic-meaning">Conclusion: Prioritize Semantic Meaning</h2>
<p>When designing components, focusing on <strong>semantic differences</strong> while reusing common structure is an excellent strategy to strike the right balance between <strong>reusability</strong> and <strong>flexibility</strong>. While it might seem like extra work upfront to create separate components like <code>ProjectCard</code> and <code>TaskCard</code>, this approach pays off in the long term by making your codebase easier to maintain, more understandable, and more adaptable as the application grows.</p>
<p>Next time you’re tempted to create a single generic component for similar-looking elements, remember: a little intentional boilerplate can save you from a lot of complexity and headaches down the road.</p>
<h3 id="heading-key-takeaways">Key Takeaways:</h3>
<ul>
<li><p><strong>Reuse Structure, Not Meaning</strong>: While components may share a layout, wrap them in distinct components (<code>ProjectCard</code>, <code>TaskCard</code>) to preserve their unique semantic purpose.</p>
</li>
<li><p><strong>Leverage Generic Components Thoughtfully</strong>: It’s fine to use generic components like <code>InfoCard</code>, but ensure they’re wrapped in more meaningful components that reflect the domain concepts.</p>
</li>
<li><p><strong>Maintain Clarity with Wrappers</strong>: Adding wrappers around shared components keeps your codebase clearer and more flexible. A <code>ProjectCard</code> can evolve independently from a <code>TaskCard</code>, even if they share structure initially.</p>
</li>
<li><p><strong>Boilerplate for Semantic Clarity</strong>: Writing a little extra wrapper code up front might seem redundant, but it ensures your components remain clear and adaptable as the application scales.</p>
</li>
<li><p><strong>Avoid Overcomplicating Generic Components</strong>: Instead of adding complex props to handle different scenarios within a generic component, wrap the generic structure in components that handle those differences separately.</p>
</li>
</ul>
]]></content:encoded></item></channel></rss>