<?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: hassantayyab</title>
    <description>The latest articles on DEV Community by hassantayyab (@hassantayyab).</description>
    <link>https://dev.to/hassantayyab</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%2F747253%2Fa7cb2eec-fdef-4e19-9ee9-d47ad9c20aeb.jpg</url>
      <title>DEV Community: hassantayyab</title>
      <link>https://dev.to/hassantayyab</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/hassantayyab"/>
    <language>en</language>
    <item>
      <title>AI Agent Tool Design: What I Wish I Knew Earlier</title>
      <dc:creator>hassantayyab</dc:creator>
      <pubDate>Sun, 08 Feb 2026 16:23:00 +0000</pubDate>
      <link>https://dev.to/hassantayyab/ai-agent-tool-design-what-i-wish-i-knew-earlier-5fj</link>
      <guid>https://dev.to/hassantayyab/ai-agent-tool-design-what-i-wish-i-knew-earlier-5fj</guid>
      <description>&lt;p&gt;I spent three days building my first AI agent, and it was terrible.&lt;/p&gt;

&lt;p&gt;Not because I chose the wrong model. Not because my prompts were bad. The agent just... didn't work. It would give vague answers, get confused by simple requests, and sometimes try to do things it clearly wasn't capable of doing.&lt;/p&gt;

&lt;p&gt;Then I discovered something that changed everything: the quality of an AI agent depends almost entirely on how you design its tools.&lt;/p&gt;

&lt;p&gt;This article is what I wish I'd read before building that first agent. If you're exploring AI agent development—whether you're an Angular developer like me looking to add AI features, or just getting started with AI engineering—this framework will save you a lot of frustration.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Are Tools in AI Agents?
&lt;/h2&gt;

&lt;p&gt;Let me start with the basics because this confused me at first.&lt;/p&gt;

&lt;p&gt;When we talk about "tools" in the context of AI agents, we're talking about functions the AI can call. That's it. Nothing fancy.&lt;/p&gt;

&lt;p&gt;Here's a simple example:&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;weatherTool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;get_weather&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Get current weather for a city&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;city&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
      &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;City name&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="na"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;city&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;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`api.weather.com/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;city&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="nx"&gt;data&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;Without this tool, if someone asks "What's the weather in Tokyo?", the agent can only say "I don't have access to current weather data."&lt;/p&gt;

&lt;p&gt;With this tool, the agent can actually call the function, get real data, and give a useful answer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tools transform your agent from a conversationalist into something that can actually do things.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is similar to how we think about components in Angular—each tool should do one thing well, and you compose them together to build something powerful.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Pattern That Changed My Approach
&lt;/h2&gt;

&lt;p&gt;After my first failed attempt, I found this framework in a book about AI engineering, and it clicked immediately:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ask yourself: "What would a human do to solve this problem?"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Then turn each step into a tool.&lt;/p&gt;

&lt;p&gt;That's it. Simple but incredibly powerful.&lt;/p&gt;

&lt;h3&gt;
  
  
  Real Example: The Book Recommendation Agent
&lt;/h3&gt;

&lt;p&gt;Let me show you an example that made this concept crystal clear for me.&lt;/p&gt;

&lt;p&gt;Imagine you're building an agent that recommends books from investor reading lists. You have a database of 10,000 books that various investors have recommended.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;My first instinct (WRONG):&lt;/strong&gt;&lt;br&gt;
Dump all 10,000 books into the agent's context and let it figure things out.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What actually happened:&lt;/strong&gt;&lt;br&gt;
The agent got completely overwhelmed. It couldn't navigate the data effectively. Recommendations were poor or generic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The better approach:&lt;/strong&gt;&lt;br&gt;
Think like a human analyst. If I were manually analyzing these book recommendations, what would I do?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Look up which investors recommended specific books&lt;/li&gt;
&lt;li&gt;Filter by genre or topic&lt;/li&gt;
&lt;li&gt;Sort by popularity (how many investors recommended it)&lt;/li&gt;
&lt;li&gt;Compare recommendations between different types of investors (founders vs VCs)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Each of these operations became a tool:&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="nx"&gt;Tools&lt;/span&gt; &lt;span class="nx"&gt;created&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nf"&gt;get_books_by_investor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;investor_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nf"&gt;get_books_by_genre&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;genre&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nf"&gt;sort_books_by_recommendations&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;books&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nf"&gt;get_investors_by_type&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="c1"&gt;// founders vs VCs&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt; The agent could now navigate the data intelligently and make genuinely good recommendations.&lt;/p&gt;

&lt;p&gt;This is exactly how I think about building features in Angular. When I'm creating a complex component, I break it down into smaller, focused services and components that each handle one responsibility. The same principle applies to AI agent tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Tool Design Matters More Than You Think
&lt;/h2&gt;

&lt;p&gt;Here's what surprised me: tool design has more impact on your agent's quality than almost anything else.&lt;/p&gt;

&lt;p&gt;You could have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Perfect prompts&lt;/li&gt;
&lt;li&gt;The best model available&lt;/li&gt;
&lt;li&gt;Great context management&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But if your tools are poorly designed, your agent will still struggle.&lt;/p&gt;

&lt;p&gt;On the flip side, with well-designed tools, even a simpler model can deliver excellent results.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tools = the capabilities of your agent.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Think of it this way: an LLM without tools is like a smart person with no hands. They can think, they can talk, but they can't actually do anything. Tools are what let your agent take action.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Framework I Now Use
&lt;/h2&gt;

&lt;p&gt;When I start building an agent, I follow this process:&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Define the Goal
&lt;/h3&gt;

&lt;p&gt;Be specific. "Build a customer support agent" is too vague.&lt;/p&gt;

&lt;p&gt;Better: "Build an agent that helps customers troubleshoot login issues, check order status, and create support tickets."&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: List Human Actions
&lt;/h3&gt;

&lt;p&gt;If a human were doing this job, what specific actions would they take?&lt;/p&gt;

&lt;p&gt;For customer support:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Look up customer account information&lt;/li&gt;
&lt;li&gt;Search help documentation&lt;/li&gt;
&lt;li&gt;Check order/subscription status&lt;/li&gt;
&lt;li&gt;Create a support ticket&lt;/li&gt;
&lt;li&gt;Send confirmation email&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Step 3: One Action = One Tool
&lt;/h3&gt;

&lt;p&gt;Each action becomes a focused tool:&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="nx"&gt;Tools&lt;/span&gt; &lt;span class="nx"&gt;needed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nf"&gt;get_customer_info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;customer_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nf"&gt;search_help_docs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nf"&gt;check_order_status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;order_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nf"&gt;create_ticket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;issue_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nf"&gt;send_email&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4: Write Clear Descriptions
&lt;/h3&gt;

&lt;p&gt;This part is crucial. The tool description isn't just for you—the agent actually reads it to decide when to use each tool.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bad description:&lt;/strong&gt;&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="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;search&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Search stuff&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;The agent thinks: "When do I use this? What does it search?"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Good description:&lt;/strong&gt;&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="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;search_help_docs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Search company help documentation for 
                troubleshooting steps. Use this when 
                customer has a technical issue. Returns 
                relevant articles with solutions.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Search terms describing the issue 
                   (e.g. 'login error', 'payment failed')&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent thinks: "Clear! Use this for technical issues, search help docs."&lt;/p&gt;

&lt;p&gt;Coming from a UX design background, I think of tool descriptions as the "interface" between the AI and your functionality. Good UX principles apply here—be clear, be specific, provide examples.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Mistakes I'm Learning to Avoid
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Mistake #1: Too Many Tools
&lt;/h3&gt;

&lt;p&gt;I made this mistake early. I thought "more tools = more capable agent."&lt;/p&gt;

&lt;p&gt;Wrong.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;With 25 tools:&lt;/strong&gt; The agent gets confused about which to use, slows down analyzing all options, and prompts get expensive.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;With 5 focused tools:&lt;/strong&gt; Clear choices, fast decisions, cheaper to run.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rule I follow now:&lt;/strong&gt; Start with 3-5 tools. Only add more when there's a clear need.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mistake #2: Vague Tool Descriptions
&lt;/h3&gt;

&lt;p&gt;Remember: the agent reads your tool descriptions to decide what to use.&lt;/p&gt;

&lt;p&gt;Vague descriptions = confused agent = poor results.&lt;/p&gt;

&lt;p&gt;Always include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What the tool does&lt;/li&gt;
&lt;li&gt;When to use it&lt;/li&gt;
&lt;li&gt;What it returns&lt;/li&gt;
&lt;li&gt;Example inputs&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Mistake #3: Tools That Do Too Much
&lt;/h3&gt;

&lt;p&gt;I initially created a &lt;code&gt;handle_customer_issue()&lt;/code&gt; tool that did everything—looked up the customer, searched docs, created tickets, sent emails.&lt;/p&gt;

&lt;p&gt;The problem: The agent couldn't control the sequence. It was a black box.&lt;/p&gt;

&lt;p&gt;Better approach: Separate tools that the agent chains together as needed. This gives the agent flexibility to handle different scenarios.&lt;/p&gt;

&lt;p&gt;It's similar to the single responsibility principle we use in Angular services—each service should do one thing well.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mistake #4: Not Testing Tools First
&lt;/h3&gt;

&lt;p&gt;This one cost me debugging time.&lt;/p&gt;

&lt;p&gt;I'd build a tool, give it to the agent, and when things failed, I wouldn't know if it was the tool or the agent logic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Better workflow:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Build tool&lt;/li&gt;
&lt;li&gt;Test tool manually (unit test it)&lt;/li&gt;
&lt;li&gt;Verify it works correctly&lt;/li&gt;
&lt;li&gt;Give to agent&lt;/li&gt;
&lt;li&gt;If agent fails now, you know it's the agent logic, not the tool&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  How Tool Calling Actually Works
&lt;/h2&gt;

&lt;p&gt;Understanding the execution loop helped me design better tools.&lt;/p&gt;

&lt;p&gt;Here's what happens when an agent runs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. User: "I can't log in to my account"

2. Agent thinks: 
   "I need to help with login. Let me check their account status."

3. Agent calls: check_account_status(user_id)

4. Tool returns: {status: "locked", reason: "too many failed attempts"}

5. Agent thinks:
   "Account is locked. I should unlock it."

6. Agent calls: unlock_account(user_id)

7. Tool returns: {success: true}

8. Agent responds:
   "I've unlocked your account. Please try logging in now."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key insight:&lt;/strong&gt; The agent decides which tools to use and when. You're not programming IF/THEN logic. The agent figures out the sequence based on the situation.&lt;/p&gt;

&lt;p&gt;This is both powerful and a bit mind-bending if you're used to traditional programming. It's more like declarative programming—you declare what tools are available, and the system figures out how to use them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical Patterns I'm Finding Useful
&lt;/h2&gt;

&lt;p&gt;As I build more agents, I'm noticing certain tool patterns that work well:&lt;/p&gt;

&lt;h3&gt;
  
  
  Data Retrieval Tools
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;get_customer_info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;search_database&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;fetch_order_history&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;customer_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Action Tools
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;send_email&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;create_ticket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;issue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;update_record&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Calculation Tools
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;calculate_total&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;convert_currency&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;amount&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;to&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;analyze_sentiment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  External API Tools
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;get_weather&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;city&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;search_web&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;translate_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;target_lang&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I'm starting to build a personal library of these patterns. When I need a new agent, I can quickly compose tools from these categories.&lt;/p&gt;

&lt;h2&gt;
  
  
  Applying This to Frontend Development
&lt;/h2&gt;

&lt;p&gt;As an Angular developer, I see parallels to how we structure applications:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bad Angular architecture:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// One giant service that does everything&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GodService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;handleEverything&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* thousands of lines */&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;Good Angular architecture:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Focused services with clear responsibilities&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AuthService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrderService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;NotificationService&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;The same principle applies to AI agent tools. Break things down into focused, composable pieces.&lt;/p&gt;

&lt;p&gt;When I'm building AI features into Angular applications now (like I did with my Angular AI Chat Kit), I think about the AI's tools the same way I think about Angular services—each should have a clear, single responsibility.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Emergent Behavior Surprise
&lt;/h2&gt;

&lt;p&gt;Here's something that surprised me: with good tool design, agents start doing creative things you didn't explicitly program.&lt;/p&gt;

&lt;p&gt;For example, with a meeting scheduler agent that has these tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;get_calendar(user_id)&lt;/li&gt;
&lt;li&gt;find_free_slots(calendar1, calendar2)&lt;/li&gt;
&lt;li&gt;create_meeting(attendees, time, duration)&lt;/li&gt;
&lt;li&gt;send_notification(user_id, message)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When someone asks "Schedule a meeting with Sarah next week", the agent figures out on its own:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Get both calendars&lt;/li&gt;
&lt;li&gt;Find overlapping free time&lt;/li&gt;
&lt;li&gt;Create the meeting&lt;/li&gt;
&lt;li&gt;Send confirmation&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You never programmed that exact sequence. The agent reasoned through it based on the tools available.&lt;/p&gt;

&lt;p&gt;This is the "magic" of good tool design—the agent becomes more capable than the sum of its tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'm Building Next
&lt;/h2&gt;

&lt;p&gt;I'm currently working on integrating AI agents into Angular applications, specifically for features in my Angular AI Chat Kit.&lt;/p&gt;

&lt;p&gt;The lessons from tool design are directly applicable:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each API endpoint becomes a potential tool&lt;/li&gt;
&lt;li&gt;Frontend state management needs to work with agent actions&lt;/li&gt;
&lt;li&gt;User interactions trigger agent workflows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'm also exploring how to make AI-assisted development workflows more efficient by treating development tasks as agent operations—code review, refactoring, documentation generation, each with specific tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;p&gt;If you're building AI agents, remember these points:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Tool quality determines agent quality&lt;/strong&gt; - spend time on tool design&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ask "What would a human do?"&lt;/strong&gt; - then make each step a tool&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Start with 3-5 tools&lt;/strong&gt; - only add more when needed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One tool = one job&lt;/strong&gt; - let the agent chain them&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write detailed descriptions&lt;/strong&gt; - the agent reads them&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test tools independently&lt;/strong&gt; - before giving to agent&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The framework is simple, but it works. I wish I'd known this before spending days debugging my first agent.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next for You?
&lt;/h2&gt;

&lt;p&gt;If you're building AI agents or adding AI features to your applications, try this framework with your next project.&lt;/p&gt;

&lt;p&gt;Start small. Build 3-5 focused tools. See what the agent can do.&lt;/p&gt;

&lt;p&gt;Then iterate. Add tools as you discover gaps in functionality.&lt;/p&gt;

&lt;p&gt;I'm still early in my AI engineering journey, but this framework has already made a huge difference in how I approach agent development. It's one of those concepts that seems obvious in hindsight but isn't intuitive when you're starting out.&lt;/p&gt;

&lt;p&gt;What are you building with AI agents? I'd love to hear about your experiences—especially if you've discovered other patterns that work well.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Make Your App Feel Instant with Optimistic Updates</title>
      <dc:creator>hassantayyab</dc:creator>
      <pubDate>Tue, 03 Feb 2026 21:35:12 +0000</pubDate>
      <link>https://dev.to/hassantayyab/why-your-app-feels-slow-and-how-optimistic-updates-fix-it-18m9</link>
      <guid>https://dev.to/hassantayyab/why-your-app-feels-slow-and-how-optimistic-updates-fix-it-18m9</guid>
      <description>&lt;p&gt;You know that tiny moment of friction when you click "like" on a post and have to wait for the heart to fill in? That split second where you're not sure if it worked? That's not just annoying—it's breaking the trust between your user and your interface.&lt;/p&gt;

&lt;p&gt;I learned this the hard way while building an AI chat feature. Users would send a message, and there'd be this awkward pause before their message appeared in the chat. Even though the API was responding in 200 milliseconds, it felt sluggish. People would click send again, thinking it didn't work. The feature was fast, but it didn't feel fast.&lt;/p&gt;

&lt;p&gt;That's when I discovered optimistic updates, and honestly, it changed how I think about building interfaces.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Actually Happens When You Wait
&lt;/h2&gt;

&lt;p&gt;Most apps work like this: user does something, you show a spinner, wait for the server to confirm, then update the UI. It's safe. It's predictable. It's also what makes your app feel like it's running through molasses.&lt;/p&gt;

&lt;p&gt;Think about it from the user's perspective. They just told your app to do something. They clicked the button. They made the decision. Why should they wait for permission from a server somewhere to see the result of their own action?&lt;/p&gt;

&lt;p&gt;The thing is, most actions succeed. Like, 99% of the time, that API call is going to return a success. So we're making users wait every single time for the 1% chance something goes wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Optimistic Approach
&lt;/h2&gt;

&lt;p&gt;Here's the mindset shift: assume the action will succeed, update the UI immediately, and deal with failures if they happen.&lt;/p&gt;

&lt;p&gt;When someone sends a message in a chat, show it in the chat right away. Make the API call in the background. If it fails (which it rarely does), you handle it gracefully. Maybe you show a little "failed to send" indicator. Maybe you let them retry. But you don't make them wait when everything is working fine.&lt;/p&gt;

&lt;p&gt;I rebuilt that AI chat feature with this pattern. Message appears instantly when you hit send. The typing animation from the AI starts right away. Behind the scenes, the message is being saved to the database, but the user doesn't need to wait for that confirmation to feel like their action worked.&lt;/p&gt;

&lt;p&gt;The difference was night and day. People stopped double-clicking send. The feature felt responsive and alive instead of sluggish and disconnected.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Delete Story
&lt;/h2&gt;

&lt;p&gt;Another place this really hit home was building a simple todo list feature. You know the drill—user clicks delete on an item, you show a loading state, call the API, then remove the item from the list.&lt;/p&gt;

&lt;p&gt;I switched it to optimistic updates. Click delete, item disappears immediately. API call happens quietly in the background. If it fails, the item reappears with a small toast notification saying "couldn't delete, try again."&lt;/p&gt;

&lt;p&gt;What surprised me was how much faster the whole interaction felt, even though the actual API timing hadn't changed at all. The perceived performance went through the roof just by not making people wait to see the result of their own decision.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Mistake Everyone Makes
&lt;/h2&gt;

&lt;p&gt;Here's what I got wrong at first, and I see this in a lot of implementations: I forgot to actually handle the error case properly.&lt;/p&gt;

&lt;p&gt;It's easy to write the happy path. Update the UI, fire the API call, done. But what happens when that call fails? If you don't store the previous state before making your optimistic update, you can't roll back. Your UI is now lying to the user, showing them something that didn't actually happen on the server.&lt;/p&gt;

&lt;p&gt;The pattern needs three things to work. First, you store the current state before making any changes. Second, you update the UI optimistically. Third, if the API call fails, you restore that previous state and tell the user what happened.&lt;/p&gt;

&lt;p&gt;Here's what that looks like in practice:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;deleteItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;itemId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Step 1: Store what we have now&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;previousItems&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="c1"&gt;// Step 2: Update UI immediately (optimistic)&lt;/span&gt;
  &lt;span class="nx"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;items&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;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;itemId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Step 3: Sync with server&lt;/span&gt;
  &lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deleteItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;itemId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&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="c1"&gt;// Success! Nothing to do, UI already 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;catch&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="c1"&gt;// Failure! Restore previous state&lt;/span&gt;
      &lt;span class="nx"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;previousItems&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nf"&gt;showToast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Failed to delete item. Please try again.&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The beautiful thing about this pattern is that it works in any framework. React, Vue, Angular, Svelte—doesn't matter. The concept is the same. Update immediately, sync later, rollback on failure.&lt;/p&gt;

&lt;h2&gt;
  
  
  When Not to Use This
&lt;/h2&gt;

&lt;p&gt;Now, before you go making every single action in your app optimistic, let's talk about when this is a bad idea.&lt;/p&gt;

&lt;p&gt;Financial transactions? Don't be optimistic. You really do need to wait for confirmation before telling someone their payment went through. Deleting important data permanently? Maybe show a confirmation dialog first, then be optimistic about the actual deletion.&lt;/p&gt;

&lt;p&gt;The rule I follow is this: if the action is easily reversible and failure is rare, be optimistic. If the action has serious consequences or you need guaranteed confirmation, wait for the server.&lt;/p&gt;

&lt;p&gt;A like button? Perfect for optimistic updates. Processing a $10,000 wire transfer? Maybe not.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Matters More Than You Think
&lt;/h2&gt;

&lt;p&gt;Here's the thing about user experience that took me a while to understand. Users don't consciously notice when things are fast. They notice when things feel slow. That 300 millisecond wait for a server response? Your users might not be able to measure it, but they feel it.&lt;/p&gt;

&lt;p&gt;Apps that use optimistic updates feel native. They feel responsive. They feel like the interface is actually listening to you instead of asking permission from a server every time you breathe.&lt;/p&gt;

&lt;p&gt;Instagram doesn't make you wait to see your like. Twitter doesn't make you wait to see your retweet. Gmail doesn't make you wait when you archive an email (but they do give you that genius undo option in case you change your mind).&lt;/p&gt;

&lt;p&gt;These apps feel fast because they trust that your actions will succeed and deal with failures as the exception, not the rule.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Implementation Reality
&lt;/h2&gt;

&lt;p&gt;When I first started using this pattern, I thought I'd need to rewrite huge chunks of my apps. Turns out, you can adopt it incrementally. Pick one feature that feels slow. Add optimistic updates to just that feature. See how it feels.&lt;/p&gt;

&lt;p&gt;Start with something low-stakes like a like button or a simple toggle. Get comfortable with the pattern of store-update-sync-rollback. Once you've done it a few times, it becomes second nature.&lt;/p&gt;

&lt;p&gt;The code isn't complicated. The mindset shift is what matters. You're moving from "ask permission, then act" to "act, then sync."&lt;/p&gt;

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

&lt;p&gt;Optimistic updates aren't some advanced technique reserved for big tech companies with massive engineering teams. It's a simple pattern that makes a massive difference in how your app feels to use.&lt;/p&gt;

&lt;p&gt;The next time you're building a feature and you catch yourself adding a loading spinner, ask yourself: does the user really need to wait for this? Can I show them the result immediately and sync in the background?&lt;/p&gt;

&lt;p&gt;More often than not, the answer is yes. And your users will thank you for it, even if they don't consciously realize why your app just feels better to use.&lt;/p&gt;




&lt;p&gt;If you found this helpful, I share more practical frontend tips and real experiences from building with modern frameworks over on &lt;a href="https://www.linkedin.com/in/hassan-t-dogar/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;. Would love to connect and hear about your own experiences with optimistic updates.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>frontend</category>
      <category>performance</category>
      <category>ux</category>
    </item>
    <item>
      <title>The Complete Guide to Prompt Engineering for Angular Developers</title>
      <dc:creator>hassantayyab</dc:creator>
      <pubDate>Sun, 18 Jan 2026 11:09:57 +0000</pubDate>
      <link>https://dev.to/hassantayyab/the-complete-guide-to-prompt-engineering-for-angular-developers-8pg</link>
      <guid>https://dev.to/hassantayyab/the-complete-guide-to-prompt-engineering-for-angular-developers-8pg</guid>
      <description>&lt;p&gt;If you've ever pasted code into an AI and gotten back something that looks like it was written in 2018, you're not alone. I spent months fighting AI outputs before realizing the problem wasn't the tool—it was how I was using it.&lt;/p&gt;

&lt;p&gt;This guide covers everything I've learned about writing prompts that actually work for Angular development. Not generic tips you'll forget tomorrow, but practical techniques you can use on your next component.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding How LLMs Actually Work
&lt;/h2&gt;

&lt;p&gt;Before we dive into techniques, you need a mental model of what's happening under the hood.&lt;/p&gt;

&lt;p&gt;An LLM is essentially a next-word prediction machine. You give it text, it predicts what should come next, then uses what it just wrote to predict the next bit, and so on. Your entire job as a prompt engineer is to set up the context so that the "next words" it predicts are the ones you actually want.&lt;/p&gt;

&lt;p&gt;When you write "create an Angular component", the model draws from everything it's seen—Angular 2 through 17, good code and bad code, tutorials and production apps. Without more context, you get an average of all of that. Usually not what you want.&lt;/p&gt;

&lt;p&gt;The key insight: prompt engineering is iterative. You write a prompt, test it, tweak the wording, add constraints, maybe include examples, and repeat until the results are reliable. There's no magic formula that works perfectly the first time.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Settings That Change Everything
&lt;/h2&gt;

&lt;p&gt;Before we get to prompt techniques, let's talk about the knobs you can adjust.&lt;/p&gt;

&lt;h3&gt;
  
  
  Temperature
&lt;/h3&gt;

&lt;p&gt;Temperature controls randomness in the output.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Low temperature (0 to 0.3)&lt;/strong&gt;: More consistent, factual, repeatable. Use this for debugging, refactors, and production code where you want the same answer every time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;High temperature (0.7 to 1.0)&lt;/strong&gt;: More variety and creativity, but also more risk of weird outputs. Use this when brainstorming component ideas or exploring architecture options.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For 90% of Angular work, I keep temperature low. When I'm stuck and want the AI to suggest approaches I haven't considered, I bump it up.&lt;/p&gt;

&lt;h3&gt;
  
  
  Token Limits
&lt;/h3&gt;

&lt;p&gt;More tokens means more output, but also more cost and sometimes more rambling. Here's the thing though—setting a low token limit doesn't magically make text concise. It just cuts it off mid-sentence.&lt;/p&gt;

&lt;p&gt;If you want brief output, you need to ask for brevity in the prompt itself: "Explain this in 3 sentences" or "Show only the changed lines."&lt;/p&gt;

&lt;h3&gt;
  
  
  Top-K and Top-P
&lt;/h3&gt;

&lt;p&gt;These control how "wide" the model looks when picking the next word.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lower values = safer, more predictable outputs&lt;/li&gt;
&lt;li&gt;Higher values = more diverse, sometimes surprising outputs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For most Angular work, the defaults are fine. But if you're getting repetitive outputs, bumping these up slightly can help.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Prompt Skeleton I Use Daily
&lt;/h2&gt;

&lt;p&gt;After trying dozens of approaches, I settled on this structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Role: You are an Angular [version] engineer.
Task: [Clear action verb] - create/debug/refactor/explain
Context: [Architecture, constraints, what already exists]
Output format: [How you want the answer structured]
Acceptance criteria: [What "done" looks like]
Edge cases: [Error handling, loading states, accessibility, tests]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's a real example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are an Angular 17 engineer.

Task: Create a notification toast component.

Context: 
- Standalone component with inline template
- Signals for state management
- TailwindCSS for styling
- Multiple toasts can stack vertically
- Auto-dismiss after configurable duration

Output: Single component file with TypeScript and inline template.

Acceptance criteria:
- Animations on enter and exit
- Click to dismiss manually
- Accessible (role="alert", aria-live="polite")
- Typed input for toast config (message, type, duration)

Edge cases:
- Handle rapid successive toasts
- Pause auto-dismiss on hover
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This takes 30 seconds to write and saves 30 minutes of cleanup.&lt;/p&gt;

&lt;h2&gt;
  
  
  Core Prompting Techniques
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Zero-Shot: Just Tell It What to Do
&lt;/h3&gt;

&lt;p&gt;The simplest approach. You describe the task without any examples.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Write an Angular pipe that formats a number as currency, 
handling null values gracefully. Return only the pipe code.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works when the task is straightforward and common. The AI has seen thousands of currency pipes and knows the pattern.&lt;/p&gt;

&lt;p&gt;Use zero-shot for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Simple utilities and pipes&lt;/li&gt;
&lt;li&gt;Standard CRUD operations&lt;/li&gt;
&lt;li&gt;Well-documented patterns&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Few-Shot: Teach By Showing
&lt;/h3&gt;

&lt;p&gt;When zero-shot gives inconsistent results, show the AI examples of what you want.&lt;/p&gt;

&lt;p&gt;This is probably my most-used technique. Instead of describing your coding conventions, you demonstrate them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Here's how we write components in this codebase:

import { Component, input, computed } from '@angular/core';

@Component({
  selector: 'app-user-avatar',
  standalone: true,
  template: `
    &amp;lt;div class="rounded-full bg-slate-200 flex items-center justify-center"
         [class]="sizeClasses()"&amp;gt;
      @if (imageUrl()) {
        &amp;lt;img [src]="imageUrl()" [alt]="name()" class="rounded-full" /&amp;gt;
      } @else {
        &amp;lt;span class="font-medium text-slate-600"&amp;gt;{{ initials() }}&amp;lt;/span&amp;gt;
      }
    &amp;lt;/div&amp;gt;
  `
})
export class UserAvatarComponent {
  name = input.required&amp;lt;string&amp;gt;();
  imageUrl = input&amp;lt;string&amp;gt;();
  size = input&amp;lt;'sm' | 'md' | 'lg'&amp;gt;('md');

  initials = computed(() =&amp;gt; 
    this.name().split(' ').map(n =&amp;gt; n[0]).join('').toUpperCase()
  );

  sizeClasses = computed(() =&amp;gt; ({
    'sm': 'w-8 h-8 text-xs',
    'md': 'w-10 h-10 text-sm', 
    'lg': 'w-14 h-14 text-base'
  })[this.size()]);
}

Now create a status-badge component following the exact same patterns:
- Same import style
- Same signal inputs with input()
- Same computed() for derived state
- Same inline template approach
- Same Tailwind conventions

The badge shows online/offline/away status with appropriate colors.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The AI sees your conventions—signal inputs, computed properties, inline templates, @if syntax, Tailwind classes—and mirrors them exactly.&lt;/p&gt;

&lt;p&gt;Rule of thumb: 1 to 3 examples for simple patterns, 3 to 5 for complex ones. More examples means more input tokens and cost, so don't overdo it.&lt;/p&gt;

&lt;h3&gt;
  
  
  System, Role, and Context Prompting
&lt;/h3&gt;

&lt;p&gt;Think of these as three layers of guidance:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;System prompting&lt;/strong&gt; sets the rules. What the model must do, how to format answers, constraints that always apply.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are an Angular code assistant. 
Always use standalone components.
Never suggest NgModules.
Format code with 2-space indentation.
Include TypeScript types for all parameters.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Role prompting&lt;/strong&gt; sets the voice and expertise level.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are a senior Angular engineer who specializes in 
performance optimization and has deep experience with 
large-scale enterprise applications.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Context prompting&lt;/strong&gt; provides the specific background for this request.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Context: This is for a dashboard application. We use 
Angular 17 with signals, TailwindCSS, and a REST API. 
The team prefers composition over inheritance.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can combine all three:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[System] You are an Angular code assistant. Use standalone components only.

[Role] Act as a senior engineer doing a code review.

[Context] This component handles user authentication in a 
healthcare app with strict HIPAA requirements.

[Task] Review this login component for security issues.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Advanced Techniques for Harder Problems
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Chain of Thought: Make It Think Step by Step
&lt;/h3&gt;

&lt;p&gt;For problems that require reasoning—debugging, complex refactors, architectural decisions—asking for step-by-step thinking dramatically improves accuracy.&lt;/p&gt;

&lt;p&gt;Without chain of thought, the AI pattern-matches to the first solution it recognizes. With it, the AI actually works through the problem.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;I'm getting this error:

ERROR NullInjectorError: No provider for UserService!

Here's my code:

// user.service.ts
@Injectable()
export class UserService {
  private http = inject(HttpClient);
  // ...
}

// user-list.component.ts
@Component({
  selector: 'app-user-list',
  standalone: true,
  imports: [CommonModule],
  template: `...`
})
export class UserListComponent {
  private userService = inject(UserService);
}

Before giving me a fix, think through this step by step:
1. What does this error message mean?
2. What are the possible causes in a standalone component setup?
3. Which cause applies to my specific code?
4. What's the fix?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This catches edge cases that quick answers miss. The AI might realize "wait, the service is @Injectable() but not providedIn: 'root'" which it wouldn't have noticed if it just jumped to a solution.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step-Back Prompting: Zoom Out, Then Zoom In
&lt;/h3&gt;

&lt;p&gt;For architectural decisions or when you're stuck, first ask a broader question to activate relevant knowledge, then apply it to your specific situation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Step 1: What are the key decision factors when choosing between 
these state management approaches in Angular 17?
- Local component state with signals
- Shared service with signals
- NgRx SignalStore
- NgRx full store

Consider: team size, app complexity, debugging needs, 
testing approach, boilerplate tolerance.

Step 2: Given my situation:
- 5 routes sharing user profile, cart, and notification data
- Team of 3 developers, one junior
- No need for time-travel debugging
- We prefer minimal boilerplate
- App will grow to ~50 components over the next year

Which approach fits best? Explain your reasoning.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This gets you a thoughtful recommendation instead of whatever the AI's training data happened to favor.&lt;/p&gt;

&lt;h3&gt;
  
  
  Self-Consistency: Same Prompt, Multiple Times
&lt;/h3&gt;

&lt;p&gt;For problems where the AI gives different answers each time, run the prompt multiple times with higher temperature and pick the most common answer.&lt;/p&gt;

&lt;p&gt;This is useful for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Classification tasks where the boundary is fuzzy&lt;/li&gt;
&lt;li&gt;Code reviews where multiple issues might exist&lt;/li&gt;
&lt;li&gt;Debugging when you're not sure which hypothesis is right&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I use this less often than other techniques, but it's valuable when you're getting inconsistent results and need confidence.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical Angular Scenarios
&lt;/h2&gt;

&lt;h3&gt;
  
  
  RxJS Prompts That Actually Work
&lt;/h3&gt;

&lt;p&gt;RxJS is where generic prompts fail hardest. "Help me with observables" gives you textbook examples that don't match your data flow.&lt;/p&gt;

&lt;p&gt;Be specific about your streams:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;I have these observables in my component:

1. this.route.params - emits { userId: string } on navigation
2. this.searchControl.valueChanges - string, already debounced 300ms
3. this.refresh$ - Subject&amp;lt;void&amp;gt; triggered on refresh button click

Desired behavior:
- Fetch user profile when userId changes
- Cancel previous user request if userId changes before it completes
- Fetch search results when search query changes OR refresh$ emits
- Cancel previous search if new search starts
- Track loading state separately for user vs search
- Error handling: 404 → show "Not found", other errors → show "Try again"

Constraints:
- Use switchMap for automatic cancellation
- Prefer declarative streams, minimize subscribe() calls
- Component uses takeUntilDestroyed() for cleanup
- All responses are typed

Show me the component class with the stream setup.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the AI can construct the actual pipeline instead of guessing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reactive Forms with Real Requirements
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Build a reactive form for user registration.

Fields:
- email (required, valid email format)
- password (required, min 12 chars, must include number and symbol)
- confirmPassword (must match password)
- acceptTerms (required, must be true)

Behavior:
- Show validation errors only after field is touched
- Disable submit until form is valid
- Password strength indicator (weak/medium/strong)

Accessibility:
- Proper labels linked to inputs
- Error messages with aria-describedby
- Focus management on validation failure

Output: Component class and template. Use Angular 17 signal-based approach 
where beneficial.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Routing and Guards
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Create a route configuration for this app structure:

- /login (public)
- /register (public)  
- /app (protected, requires auth)
  - /app/dashboard (default child)
  - /app/users (lazy loaded)
  - /app/users/:id (user detail)
  - /app/settings (lazy loaded)

Requirements:
- Auth guard redirects to /login if not authenticated
- Already authenticated users visiting /login redirect to /app
- Lazy load the users and settings features
- Use standalone routing APIs

Output:
1. app.routes.ts
2. Auth guard
3. Brief explanation of the navigation flow
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Component Generation with Consistency
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;I need to generate a complete feature module for "Products".

Routes: /products (list), /products/new (create), /products/:id (detail/edit)
API endpoints: GET /api/products, POST /api/products, 
GET /api/products/:id, PUT /api/products/:id, DELETE /api/products/:id

Follow this existing component as the pattern:
[paste your best existing feature component]

Generate:
1. products.routes.ts
2. product-list.component.ts (with pagination, search filter)
3. product-detail.component.ts (view/edit mode toggle)
4. product-form.component.ts (reusable for create/edit)
5. products.service.ts
6. product.model.ts

Show the file tree first, then each file with clear separation.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Structured Output: Getting JSON Back
&lt;/h2&gt;

&lt;p&gt;When you need data extraction or structured responses, asking for JSON reduces hallucination and makes parsing easy.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Analyze this Angular component and return a JSON assessment:

[paste component code]

Return valid JSON only with this structure:
{
  "complexity": "low" | "medium" | "high",
  "issues": [
    {
      "type": "performance" | "accessibility" | "maintainability",
      "description": "...",
      "suggestion": "...",
      "priority": "low" | "medium" | "high"
    }
  ],
  "positives": ["...", "..."],
  "overallScore": 1-10
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One warning: if you're hitting token limits, JSON can get cut off mid-structure. Either increase limits or ask for more concise output.&lt;/p&gt;

&lt;h2&gt;
  
  
  Best Practices Summary
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Provide examples.&lt;/strong&gt; Few-shot beats lengthy explanations almost every time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Keep prompts clear.&lt;/strong&gt; If it confuses you, it'll confuse the model. Rewrite until it's simple.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Be specific about output.&lt;/strong&gt; Don't say "write a component." Say what kind, how long, what patterns to follow, what to include.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prefer instructions over constraints.&lt;/strong&gt; "Include only X, Y, Z" works better than "Don't do A, don't do B, don't do C." But constraints are still useful for hard rules.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Control length deliberately.&lt;/strong&gt; Use token limits AND explicit instructions ("explain in 3 sentences").&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use variables for reusable prompts.&lt;/strong&gt; If you're generating similar code often, template it: "Create a {entityName} service following the pattern above."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Experiment with phrasing.&lt;/strong&gt; Questions, statements, and commands can all give different results. Try variations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mix your examples.&lt;/strong&gt; For classification tasks, don't put all the positive examples first. Interleave them so the model learns the concept, not the order.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Document what works.&lt;/strong&gt; Keep a file of prompts that give good results. Future you will thank past you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Re-test after model updates.&lt;/strong&gt; When the AI provider releases a new version, your prompts might need adjustment.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Emergency Prompt
&lt;/h2&gt;

&lt;p&gt;When you're completely stuck, use this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;I'm stuck. Here's everything:

Goal: [what should happen]
Current code: [relevant files]
Actual behavior: [what's happening vs expected]
Error message: [if any]
What I've tried: [your attempts so far]
Constraints: [Angular version, libraries, patterns required]

Please:
1. Restate the problem in your own words so I know you understand
2. List 3 possible causes
3. Pick the most likely and explain why
4. Show the fix with minimal changes
5. Tell me how to verify it worked
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This forces the AI to engage with your specific situation instead of pattern-matching to a generic solution.&lt;/p&gt;

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

&lt;p&gt;Prompt engineering isn't about memorizing magic phrases. It's about recognizing that the AI is context-blind and your job is to provide that context.&lt;/p&gt;

&lt;p&gt;Every prompt is a knowledge transfer. You're teaching the AI enough about your project, your conventions, and your specific problem that its predictions land on the patterns you actually want.&lt;/p&gt;

&lt;p&gt;Get good at that transfer, and AI becomes a genuine force multiplier. Skip it, and you'll spend more time fixing AI output than you would have spent writing the code yourself.&lt;/p&gt;

&lt;p&gt;The techniques in this guide work. But they work best when you experiment, iterate, and build your own library of prompts that fit your specific workflow.&lt;/p&gt;

&lt;p&gt;Start with the prompt skeleton. Add few-shot examples from your own codebase. Use chain of thought when debugging. Be embarrassingly specific with RxJS.&lt;/p&gt;

&lt;p&gt;Your future self—and your deadline—will thank you.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;What prompting techniques have worked for your Angular projects? I'm always looking to learn from others. Connect with me on LinkedIn or X.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>angular</category>
      <category>webdev</category>
      <category>ai</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Agent Skills: How to Make AI Write Modern Angular Code</title>
      <dc:creator>hassantayyab</dc:creator>
      <pubDate>Fri, 16 Jan 2026 23:15:31 +0000</pubDate>
      <link>https://dev.to/hassantayyab/agent-skills-how-to-make-ai-write-modern-angular-code-3h5i</link>
      <guid>https://dev.to/hassantayyab/agent-skills-how-to-make-ai-write-modern-angular-code-3h5i</guid>
      <description>&lt;h2&gt;
  
  
  Agent Skills: Teaching Your AI Coding Assistant to Write Better Angular Code
&lt;/h2&gt;

&lt;p&gt;If you've used AI coding assistants like Claude Code, Cursor, or GitHub Copilot, you've probably noticed something frustrating: they often generate outdated code. Ask for an Angular component, and you might get constructor-based dependency injection instead of the modern &lt;code&gt;inject()&lt;/code&gt; function, or &lt;code&gt;*ngIf&lt;/code&gt; instead of the new &lt;code&gt;@if&lt;/code&gt; control flow. This happens because these AI models were trained on code from a specific point in time, and frameworks like Angular evolve rapidly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Agent Skills&lt;/strong&gt; solve this problem. They're simple instruction files that teach AI assistants how to write code the way &lt;em&gt;you&lt;/em&gt; want it written.&lt;/p&gt;

&lt;h2&gt;
  
  
  What exactly is an Agent Skill?
&lt;/h2&gt;

&lt;p&gt;Think of an Agent Skill like a recipe card you hand to a chef. The chef (the AI) already knows how to cook, but the recipe card tells them exactly how &lt;em&gt;you&lt;/em&gt; want your dish prepared—which ingredients to use, which to avoid, and what the final result should look like.&lt;/p&gt;

&lt;p&gt;In technical terms, a skill is just a markdown file named &lt;code&gt;SKILL.md&lt;/code&gt; that contains instructions for the AI. When you ask the AI to do something that matches a skill's purpose, it reads those instructions and follows them.&lt;/p&gt;

&lt;p&gt;Here's the simplest possible skill:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-angular-skill&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Use&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;when&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;creating&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Angular&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;components&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;or&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;services."&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="gh"&gt;# Angular Rules&lt;/span&gt;

Always use the &lt;span class="sb"&gt;`inject()`&lt;/span&gt; function for dependency injection.
Never use constructor injection.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. When the AI recognizes you're working on Angular code, it reads this file and follows the rules.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why do Angular developers need skills?
&lt;/h2&gt;

&lt;p&gt;Angular has changed dramatically in recent versions. The patterns that were correct in Angular 14 are now deprecated in Angular 18 and beyond. Without guidance, AI assistants will generate a mix of old and new patterns because their training data contains years of Angular code written in different styles.&lt;/p&gt;

&lt;p&gt;Here's what typically happens without a skill:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You ask:&lt;/strong&gt; "Create a user service that fetches data from an API"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI generates (outdated pattern):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;providedIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&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="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HttpClient&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;  &lt;span class="c1"&gt;// ❌ Old pattern&lt;/span&gt;

  &lt;span class="nf"&gt;getUsers&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&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;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/users&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What you actually want (modern pattern):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;providedIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&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="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;HttpClient&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// ✅ Modern pattern&lt;/span&gt;

  &lt;span class="nf"&gt;getUsers&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&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;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/users&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The difference seems small, but multiply this across an entire codebase and you end up with inconsistent code that mixes patterns from different Angular eras.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating your first Angular skill
&lt;/h2&gt;

&lt;p&gt;Let's build a practical skill that enforces modern Angular patterns. Create a folder called &lt;code&gt;.claude/skills/angular-modern/&lt;/code&gt; in your project root, then add a &lt;code&gt;SKILL.md&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;angular-modern-patterns&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Generate Angular 18+ code using signals, standalone components,&lt;/span&gt; 
             &lt;span class="s"&gt;and inject(). Use when creating components, services, directives,&lt;/span&gt;
             &lt;span class="s"&gt;or refactoring existing Angular code.&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="gh"&gt;# Modern Angular Development Patterns&lt;/span&gt;

When writing Angular code, follow these patterns consistently.

&lt;span class="gu"&gt;## Dependency Injection&lt;/span&gt;

Use the &lt;span class="sb"&gt;`inject()`&lt;/span&gt; function instead of constructor injection:

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;br&gt;
// ✅ Correct - use this pattern&lt;br&gt;
export class UserComponent {&lt;br&gt;
  private userService = inject(UserService);&lt;br&gt;
  private router = inject(Router);&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;// ❌ Wrong - never generate this&lt;br&gt;
export class UserComponent {&lt;br&gt;
  constructor(&lt;br&gt;
    private userService: UserService,&lt;br&gt;
    private router: Router&lt;br&gt;
  ) {}&lt;br&gt;
}&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
## Components

All components must be standalone. In Angular v20+, omit `standalone: true` 
since it's the default:

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;br&gt;
// ✅ Correct for Angular 20+&lt;br&gt;
@Component({&lt;br&gt;
  selector: 'app-user-card',&lt;br&gt;
  changeDetection: ChangeDetectionStrategy.OnPush,&lt;br&gt;
  imports: [CommonModule],&lt;br&gt;
  template: &lt;code&gt;...&lt;/code&gt;&lt;br&gt;
})&lt;br&gt;
export class UserCardComponent {&lt;br&gt;
  // Use signal inputs instead of @Input decorator&lt;br&gt;
  user = input.required();&lt;/p&gt;

&lt;p&gt;// Use output function instead of @Output decorator&lt;br&gt;&lt;br&gt;
  userSelected = output();&lt;br&gt;
}&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
## Control Flow

Use the new built-in control flow syntax instead of structural directives:

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;br&gt;
// ✅ Correct - new control flow&lt;br&gt;
@if (user()) {&lt;br&gt;
  &lt;br&gt;
} &lt;a class="mentioned-user" href="https://dev.to/else"&gt;@else&lt;/a&gt; {&lt;br&gt;
  &lt;/p&gt;
&lt;p&gt;No user found&lt;/p&gt;
&lt;br&gt;
}

&lt;p&gt;&lt;a class="mentioned-user" href="https://dev.to/for"&gt;@for&lt;/a&gt; (item of items(); track item.id) {&lt;br&gt;
  &lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;// ❌ Wrong - old directives&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
## Signals for State

Prefer signals over plain properties for reactive state:

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;br&gt;
export class CounterComponent {&lt;br&gt;
  // ✅ Correct - signals for reactive state&lt;br&gt;
  count = signal(0);&lt;br&gt;
  doubleCount = computed(() =&amp;gt; this.count() * 2);&lt;/p&gt;

&lt;p&gt;increment() {&lt;br&gt;
    this.count.update(c =&amp;gt; c + 1);&lt;br&gt;
  }&lt;br&gt;
}&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
Save this file, and now every time you ask the AI to generate Angular code, it will follow these patterns.

## How skills actually work under the hood

When you start a conversation with Claude Code (or another skill-enabled AI), here's what happens:

1. **Metadata loading:** The AI reads just the `name` and `description` from each skill file. This costs very few tokens—roughly 50-100 per skill.
2. **Pattern matching:** When you make a request, the AI checks if any skill descriptions match what you're asking for. "Create an Angular component" matches our skill's description about creating components.
3. **Full loading:** Only when there's a match does the AI read the complete skill instructions. This keeps conversations efficient—you're not paying for unused context.
4. **Code generation:** The AI follows the skill's instructions when generating its response.

This "progressive disclosure" design means you can have dozens of skills installed without slowing anything down. The AI only loads what it needs.

## Organizing skills for a real Angular project

For a production Angular application, you'll likely want several skills working together. Here's a practical folder structure:

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;your-angular-project/&lt;br&gt;
├── .claude/&lt;br&gt;
│   └── skills/&lt;br&gt;
│       ├── angular-modern/&lt;br&gt;
│       │   └── SKILL.md          # Core patterns we created above&lt;br&gt;
│       ├── component-generator/&lt;br&gt;
│       │   ├── SKILL.md          # Component scaffolding workflow&lt;br&gt;
│       │   └── templates/&lt;br&gt;
│       │       └── component.ts  # Template file for reference&lt;br&gt;
│       ├── ngrx-patterns/&lt;br&gt;
│       │   └── SKILL.md          # State management conventions&lt;br&gt;
│       └── testing/&lt;br&gt;
│           └── SKILL.md          # Jest and TestBed patterns&lt;br&gt;
├── CLAUDE.md                     # Project-level context (always loaded)&lt;br&gt;
└── src/&lt;br&gt;
    └── ...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
The `CLAUDE.md` file at your project root is special—it loads automatically for every conversation and should contain high-level project context:

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
markdown&lt;/p&gt;
&lt;h1&gt;
  
  
  Project: Customer Portal
&lt;/h1&gt;
&lt;h2&gt;
  
  
  Tech Stack
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Angular 20&lt;/li&gt;
&lt;li&gt;NgRx Signals for state management&lt;/li&gt;
&lt;li&gt;Angular Material with custom theme&lt;/li&gt;
&lt;li&gt;Jest for testing&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Conventions
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;All components use OnPush change detection&lt;/li&gt;
&lt;li&gt;Feature modules organized by domain (users, orders, products)&lt;/li&gt;
&lt;li&gt;API calls go through services, never directly in components&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Commands
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;npm run test&lt;/code&gt; - Run unit tests&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;npm run e2e&lt;/code&gt; - Run Playwright tests&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;npm run lint&lt;/code&gt; - Check code style
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
## A complete example: Component generation workflow

Let's create a more advanced skill that handles a common workflow—generating a complete Angular feature with a component, service, and tests.

Create `.claude/skills/feature-generator/SKILL.md`:

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  markdown
&lt;/h2&gt;

&lt;p&gt;name: angular-feature-generator&lt;br&gt;
description: Generate complete Angular features including component, service, &lt;br&gt;
             and tests. Use when asked to create a new feature, page, or &lt;/p&gt;
&lt;h2&gt;
  
  
               module for the application.
&lt;/h2&gt;
&lt;h1&gt;
  
  
  Angular Feature Generation
&lt;/h1&gt;

&lt;p&gt;When asked to create a new feature, generate these files in order:&lt;/p&gt;
&lt;h2&gt;
  
  
  1. Service (data layer first)
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// feature-name.service.ts&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;inject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Injectable&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="s1"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&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;HttpClient&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="s1"&gt;@angular/common/http&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="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;providedIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&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="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FeatureNameService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;HttpClient&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Methods return Observables for flexibility&lt;/span&gt;
  &lt;span class="c1"&gt;// Components convert to signals as needed&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  2. Component (presentation layer)
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// feature-name.component.ts&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;ChangeDetectionStrategy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;inject&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="s1"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&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;toSignal&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="s1"&gt;@angular/core/rxjs-interop&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="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-feature-name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;changeDetection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ChangeDetectionStrategy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OnPush&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;  &lt;span class="c1"&gt;// Add required imports&lt;/span&gt;
  &lt;span class="na"&gt;template&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;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FeatureNameComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;featureService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;FeatureNameService&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Convert service observables to signals for template&lt;/span&gt;
  &lt;span class="c1"&gt;// data = toSignal(this.featureService.getData());&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  3. Test file
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// feature-name.component.spec.ts&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;ComponentFixture&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;TestBed&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="s1"&gt;@angular/core/testing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&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;provideHttpClientTesting&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="s1"&gt;@angular/common/http/testing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;FeatureNameComponent&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FeatureNameComponent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="na"&gt;fixture&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ComponentFixture&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;FeatureNameComponent&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;beforeEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &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;await&lt;/span&gt; &lt;span class="nx"&gt;TestBed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configureTestingModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;FeatureNameComponent&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;provideHttpClientTesting&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt;
    &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;compileComponents&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nx"&gt;fixture&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;TestBed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;FeatureNameComponent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;component&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fixture&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;componentInstance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should create&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeTruthy&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;h2&gt;
  
  
  File organization
&lt;/h2&gt;

&lt;p&gt;Place generated files in the appropriate feature folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/app/features/feature-name/
├── feature-name.component.ts
├── feature-name.component.spec.ts
├── feature-name.service.ts
└── feature-name.service.spec.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now when you ask "Create a user profile feature," the AI knows exactly what files to generate, in what order, and following which patterns.&lt;/p&gt;

&lt;h2&gt;
  
  
  Skills versus other AI extension methods
&lt;/h2&gt;

&lt;p&gt;You might wonder how skills compare to other ways of extending AI assistants, like MCP servers or function calling. They serve different purposes and work well together:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Skills&lt;/strong&gt; teach the AI &lt;em&gt;how&lt;/em&gt; to approach tasks. They provide patterns, conventions, and domain knowledge. Skills are static instruction files that get loaded into the conversation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MCP (Model Context Protocol)&lt;/strong&gt; connects the AI &lt;em&gt;to&lt;/em&gt; external systems. An MCP server might give the AI access to your Figma designs, your GitHub repository, or a live database. MCP provides dynamic, real-time data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Function calling&lt;/strong&gt; lets the AI &lt;em&gt;execute&lt;/em&gt; specific actions, like running a calculation or calling an API endpoint.&lt;/p&gt;

&lt;p&gt;For Angular development, a practical setup might combine all three:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Skill:&lt;/strong&gt; Teaches the AI your component patterns and coding standards&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MCP server:&lt;/strong&gt; Connects to Figma so the AI can see your designs while generating components
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Function:&lt;/strong&gt; Runs &lt;code&gt;ng generate&lt;/code&gt; commands to actually create the files&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Getting started today
&lt;/h2&gt;

&lt;p&gt;Here's a practical path to start using skills in your Angular projects:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1:&lt;/strong&gt; Create the &lt;code&gt;.claude/skills/&lt;/code&gt; folder in your project root.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2:&lt;/strong&gt; Add a basic Angular patterns skill using the example from this post.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3:&lt;/strong&gt; Create a &lt;code&gt;CLAUDE.md&lt;/code&gt; file documenting your project's tech stack and conventions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4:&lt;/strong&gt; Test it by asking the AI to generate a component and verify it follows your patterns.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 5:&lt;/strong&gt; Iterate. When the AI generates something wrong, add a rule to your skill to prevent it next time.&lt;/p&gt;

&lt;p&gt;The Angular team has also published official AI configuration that you can generate with &lt;code&gt;ng new&lt;/code&gt; in Angular CLI v20.2+. This gives you a solid starting point that you can customize for your team's specific conventions.&lt;/p&gt;

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

&lt;p&gt;Agent Skills transform AI coding assistants from generic code generators into specialized development partners that understand your project's conventions. For Angular developers dealing with rapidly evolving framework patterns, skills ensure the AI generates modern, consistent code instead of a mixture of deprecated approaches.&lt;/p&gt;

&lt;p&gt;The investment is minimal—a few markdown files—but the payoff is significant. Instead of constantly correcting AI-generated code, you teach the AI once and it follows your patterns consistently. As your conventions evolve, you update the skill files and every future interaction reflects those changes.&lt;/p&gt;

&lt;p&gt;Start small with a single skill covering your most important patterns, and expand from there as you identify more opportunities for guidance.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>beginners</category>
      <category>angular</category>
    </item>
    <item>
      <title>How I Get Better UI from Claude: Research First, Build Second</title>
      <dc:creator>hassantayyab</dc:creator>
      <pubDate>Mon, 12 Jan 2026 09:39:11 +0000</pubDate>
      <link>https://dev.to/hassantayyab/how-i-get-better-ui-from-claude-research-first-build-second-12f</link>
      <guid>https://dev.to/hassantayyab/how-i-get-better-ui-from-claude-research-first-build-second-12f</guid>
      <description>&lt;p&gt;Most AI-generated UIs look the same. You know the vibe — generic gradients, overused shadows, that "I was clearly made by AI" aesthetic you see in every vibe-coded app.&lt;/p&gt;

&lt;p&gt;I found a simple workflow that fixes this. It takes an extra 5 minutes but the output looks like it came from an actual designer.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem with "Build Me a Component"
&lt;/h2&gt;

&lt;p&gt;When you ask Claude to build a UI component directly, it pulls from its training data. That means you get a mix of patterns it's seen — some good, some dated, some just weird.&lt;/p&gt;

&lt;p&gt;I was building a typing indicator for my Angular AI UI component library. You know, those animated dots that show when the AI is thinking.&lt;/p&gt;

&lt;p&gt;My first instinct was to just ask Claude to build it.&lt;/p&gt;

&lt;p&gt;The result? Functional, but forgettable. Three bouncing dots that looked like every tutorial example from 2019.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Fix: Make Claude a Design Researcher First
&lt;/h2&gt;

&lt;p&gt;Instead of jumping straight to code, I added one step.&lt;/p&gt;

&lt;p&gt;I asked Claude Code (using Opus 4.5 in research mode) to research the problem first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Research how typing indicators are used in modern web apps, 
especially AI chats like ChatGPT, Claude, and Gemini. 
Look at design patterns, animations, and how they signal 
different states.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Giving it specific examples of well-designed apps makes a huge difference. Claude now has a reference point for what "good" looks like in this specific context.&lt;/p&gt;

&lt;p&gt;The research came back with insights I wouldn't have thought to look for — how ChatGPT uses a pulsing effect vs Claude's shimmer animation, how Gemini handles the transition between thinking and responding, accessibility considerations for motion-sensitive users.&lt;/p&gt;




&lt;h2&gt;
  
  
  Then Feed the Research Back
&lt;/h2&gt;

&lt;p&gt;Here's the key part.&lt;/p&gt;

&lt;p&gt;I take the entire research document and paste it into a new conversation. Then I ask Claude to build the component with this context.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Based on this research, build me a typing indicator component 
for Angular that follows modern AI chat patterns. Make it 
polished and professional.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The difference is night and day.&lt;/p&gt;

&lt;p&gt;Instead of generic bouncing dots, I got a component with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Subtle animation timing that felt natural&lt;/li&gt;
&lt;li&gt;Smooth state transitions&lt;/li&gt;
&lt;li&gt;Design choices that actually made sense for an AI chat context&lt;/li&gt;
&lt;li&gt;Details I wouldn't have specified myself&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It looked like something that belongs in a production app, not a weekend hackathon.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Works
&lt;/h2&gt;

&lt;p&gt;Claude is good at following patterns. The problem is which patterns it follows.&lt;/p&gt;

&lt;p&gt;When you ask it to build something from scratch, it averages across everything it knows. You get median design quality — safe, boring, forgettable.&lt;/p&gt;

&lt;p&gt;When you give it focused research on how the best apps solve this exact problem, it has a much tighter reference point. It's not guessing anymore. It's applying specific patterns from apps you actually want to emulate.&lt;/p&gt;

&lt;p&gt;Think of it like this: asking Claude to "design a button" vs asking it to "design a button like Stripe's dashboard" gives you completely different results. Research mode just automates finding those references.&lt;/p&gt;




&lt;h2&gt;
  
  
  My Workflow Now
&lt;/h2&gt;

&lt;p&gt;For any UI component that needs to look good:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1:&lt;/strong&gt; Ask Claude (Opus 4.5, research mode) to research the problem&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Research how [component] is implemented in modern apps like 
[2-3 specific well-designed examples]. Focus on design patterns, 
animations, and UX details.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2:&lt;/strong&gt; Review the research (sometimes it surfaces things I didn't know to ask for)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3:&lt;/strong&gt; Paste the full research document into a new conversation&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4:&lt;/strong&gt; Ask Claude to build with that context&lt;/p&gt;

&lt;p&gt;The extra 5 minutes of research saves hours of tweaking generic output into something that actually looks professional.&lt;/p&gt;




&lt;h2&gt;
  
  
  When I Use This
&lt;/h2&gt;

&lt;p&gt;I don't do this for every component. Simple stuff like form fields or basic layouts — Claude handles those fine without research.&lt;/p&gt;

&lt;p&gt;But for anything that needs to feel polished:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Complex interactive components&lt;/li&gt;
&lt;li&gt;Animations and micro-interactions&lt;/li&gt;
&lt;li&gt;Components where "feel" matters (chat UIs, dashboards, onboarding flows)&lt;/li&gt;
&lt;li&gt;Anything users will see repeatedly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's when research-first pays off.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Bigger Point
&lt;/h2&gt;

&lt;p&gt;AI-assisted development isn't just about speed. It's about using AI at the right step.&lt;/p&gt;

&lt;p&gt;Most people use Claude as a code generator. But it's also a researcher, a design consultant, and a pattern library — if you prompt it that way.&lt;/p&gt;

&lt;p&gt;The typing indicator I built is now one of the best-looking components in my library. Not because I'm a designer, but because I let Claude do the design research before writing a single line of code.&lt;/p&gt;

&lt;p&gt;Try it on your next UI component. Research first, build second.&lt;/p&gt;




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

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://platform.claude.com/docs/en/home" rel="noopener noreferrer"&gt;Claude Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hassantayyab.com/blogs/claude-code-tips-ai-assisted-development" rel="noopener noreferrer"&gt;My AI-assisted development setup&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>productivity</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Stop Wasting Tokens on UI Bugs: How Chrome DevTools MCP Changed My Debugging Workflow</title>
      <dc:creator>hassantayyab</dc:creator>
      <pubDate>Thu, 08 Jan 2026 12:00:54 +0000</pubDate>
      <link>https://dev.to/hassantayyab/stop-wasting-tokens-on-ui-bugs-how-chrome-devtools-mcp-changed-my-debugging-workflow-3ma9</link>
      <guid>https://dev.to/hassantayyab/stop-wasting-tokens-on-ui-bugs-how-chrome-devtools-mcp-changed-my-debugging-workflow-3ma9</guid>
      <description>&lt;h2&gt;
  
  
  Stop Wasting Tokens on UI Bugs: How Chrome DevTools MCP Changed My Debugging Workflow
&lt;/h2&gt;

&lt;p&gt;There's a frustrating pattern when using AI for frontend development.&lt;/p&gt;

&lt;p&gt;You describe a UI bug. Claude tries to fix it. Doesn't work. You describe it again, maybe paste some CSS. Still doesn't work. Claude keeps guessing, trying different things, burning through tokens while you watch the same broken UI.&lt;/p&gt;

&lt;p&gt;The problem is simple: &lt;strong&gt;AI can't fix what it can't see.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I found a solution that cuts my UI debugging time in half. Sometimes more.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem: Blind Debugging
&lt;/h2&gt;

&lt;p&gt;A few weeks ago I had a scrollbar that wouldn't hide. Simple enough, right?&lt;/p&gt;

&lt;p&gt;I told Claude to hide the scrollbar on a long list of items. It added &lt;code&gt;overflow: hidden&lt;/code&gt;. Didn't work. Tried &lt;code&gt;::-webkit-scrollbar { display: none }&lt;/code&gt;. Still showing. Added &lt;code&gt;scrollbar-width: none&lt;/code&gt;. Nothing.&lt;/p&gt;

&lt;p&gt;Claude kept trying different CSS combinations. I kept saying "still not working." We went back and forth, wasting tokens, getting nowhere.&lt;/p&gt;

&lt;p&gt;The issue? Claude was guessing based on code. It couldn't actually see what was rendering in the browser.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Fix: Give AI Eyes
&lt;/h2&gt;

&lt;p&gt;Chrome DevTools MCP lets Claude actually interact with your running application. It can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Launch your app&lt;/li&gt;
&lt;li&gt;Open Chrome&lt;/li&gt;
&lt;li&gt;Click around and reproduce scenarios&lt;/li&gt;
&lt;li&gt;Take screenshots&lt;/li&gt;
&lt;li&gt;Inspect the actual rendered DOM&lt;/li&gt;
&lt;li&gt;See computed styles&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of guessing from code, it can see exactly what you're seeing.&lt;/p&gt;




&lt;h2&gt;
  
  
  How It Actually Works
&lt;/h2&gt;

&lt;p&gt;Here's what happened when I used Chrome DevTools MCP for that scrollbar issue.&lt;/p&gt;

&lt;p&gt;I told Claude: "use the mcp server to fix this"&lt;/p&gt;

&lt;p&gt;Then it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Started my dev server&lt;/li&gt;
&lt;li&gt;Opened Chrome to the app&lt;/li&gt;
&lt;li&gt;Added items to the list one by one to reproduce the scenario&lt;/li&gt;
&lt;li&gt;Took a screenshot of the UI&lt;/li&gt;
&lt;li&gt;Saw the actual problem&lt;/li&gt;
&lt;li&gt;Fixed it&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I didn't click anything. I just watched Chrome doing stuff on its own and made sure not to close it.&lt;/p&gt;

&lt;p&gt;The fix was instant once Claude could actually see the rendered output.&lt;/p&gt;




&lt;h2&gt;
  
  
  Another Example: The Mysterious Textarea Outline
&lt;/h2&gt;

&lt;p&gt;I had a chat input component with a textarea wrapped in a div. There was an outline appearing that I wanted gone.&lt;/p&gt;

&lt;p&gt;Claude kept targeting the textarea styles within the component. Didn't work. Tried different border and outline properties. Still there.&lt;/p&gt;

&lt;p&gt;When I had it use Chrome DevTools MCP, it could inspect the computed styles and discovered global styles were interfering. The component styles were encapsulated, but something in the global CSS was adding the outline.&lt;/p&gt;

&lt;p&gt;Once Claude could see the actual cascade of styles hitting that element, the fix was obvious.&lt;/p&gt;




&lt;h2&gt;
  
  
  When to Use This
&lt;/h2&gt;

&lt;p&gt;I don't use Chrome DevTools MCP for everything. Most UI work Claude handles fine from code alone.&lt;/p&gt;

&lt;p&gt;But when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Claude keeps trying fixes that don't work&lt;/li&gt;
&lt;li&gt;You're going back and forth with no progress&lt;/li&gt;
&lt;li&gt;The issue involves visual state that's hard to describe&lt;/li&gt;
&lt;li&gt;Something is overriding styles and you can't figure out what&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's when I tell it to use the MCP server. Usually fixes things immediately.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Workflow
&lt;/h2&gt;

&lt;p&gt;It's surprisingly simple.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;My prompt when Claude is stuck:&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;use the mcp server to fix this
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. Claude handles the rest:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Runs the app on a port&lt;/li&gt;
&lt;li&gt;Opens Chrome&lt;/li&gt;
&lt;li&gt;Navigates to the right page&lt;/li&gt;
&lt;li&gt;Interacts with the UI to reproduce the issue&lt;/li&gt;
&lt;li&gt;Takes screenshots automatically&lt;/li&gt;
&lt;li&gt;Inspects what it needs to&lt;/li&gt;
&lt;li&gt;Fixes the problem&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Just make sure Chrome is open and don't close it while Claude is working. If you interrupt the process, it breaks.&lt;/p&gt;




&lt;h2&gt;
  
  
  Setting It Up
&lt;/h2&gt;

&lt;p&gt;Setup is straightforward. I followed the official docs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For Claude Code / Claude Desktop:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Check the official MCP documentation:&lt;br&gt;
&lt;a href="https://modelcontextprotocol.io/docs/develop/connect-local-servers" rel="noopener noreferrer"&gt;https://modelcontextprotocol.io/docs/develop/connect-local-servers&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For Cursor:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Cursor has its own MCP setup process:&lt;br&gt;
&lt;a href="https://cursor.com/docs/context/mcp" rel="noopener noreferrer"&gt;https://cursor.com/docs/context/mcp&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Chrome DevTools MCP server:&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://github.com/ChromeDevTools/chrome-devtools-mcp" rel="noopener noreferrer"&gt;https://github.com/ChromeDevTools/chrome-devtools-mcp&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Follow the steps, connect the server, and you're good to go.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Saves So Much Time
&lt;/h2&gt;

&lt;p&gt;When AI is stuck on a UI bug, it enters a frustrating loop:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Claude tries something&lt;/li&gt;
&lt;li&gt;You say it didn't work&lt;/li&gt;
&lt;li&gt;Claude tries something else&lt;/li&gt;
&lt;li&gt;Still doesn't work&lt;/li&gt;
&lt;li&gt;Repeat until you give up or get lucky&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Each cycle wastes tokens and time. And often Claude is just guessing because it can't see the actual problem.&lt;/p&gt;

&lt;p&gt;Chrome MCP breaks this loop. Instead of guessing, Claude can see. The fix usually comes on the first try.&lt;/p&gt;

&lt;p&gt;For me, this saves at least half the debugging time on visual issues. Sometimes way more.&lt;/p&gt;




&lt;h2&gt;
  
  
  Limitations
&lt;/h2&gt;

&lt;p&gt;It's not magic. A few things to know:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You need to keep Chrome open while it works&lt;/li&gt;
&lt;li&gt;It's overkill for simple CSS fixes Claude can handle from code&lt;/li&gt;
&lt;li&gt;Sometimes the automation is slower than just fixing it yourself if you already know the issue&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use it when you're stuck, not for everything.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Takeaway
&lt;/h2&gt;

&lt;p&gt;Most AI coding frustration comes from the AI not being able to see what you're seeing.&lt;/p&gt;

&lt;p&gt;For UI bugs, Chrome DevTools MCP fixes this. Claude can actually run your app, look at the screen, inspect elements, and understand what's happening.&lt;/p&gt;

&lt;p&gt;Next time you're going back and forth on a visual bug that Claude can't seem to fix, just tell it to use the MCP server.&lt;/p&gt;

&lt;p&gt;You'll wonder why you didn't set this up sooner.&lt;/p&gt;




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

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://modelcontextprotocol.io/docs/develop/connect-local-servers" rel="noopener noreferrer"&gt;MCP Local Servers Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ChromeDevTools/chrome-devtools-mcp" rel="noopener noreferrer"&gt;Chrome DevTools MCP Server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cursor.com/docs/context/mcp" rel="noopener noreferrer"&gt;Cursor MCP Docs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>webdev</category>
      <category>frontend</category>
    </item>
    <item>
      <title>How I 10x'd My Development Speed with Claude Code</title>
      <dc:creator>hassantayyab</dc:creator>
      <pubDate>Mon, 05 Jan 2026 10:55:50 +0000</pubDate>
      <link>https://dev.to/hassantayyab/how-i-10xd-my-development-speed-with-claude-code-a-system-for-ai-assisted-coding-that-actually-3f07</link>
      <guid>https://dev.to/hassantayyab/how-i-10xd-my-development-speed-with-claude-code-a-system-for-ai-assisted-coding-that-actually-3f07</guid>
      <description>&lt;p&gt;&lt;em&gt;After 6 months of daily Claude Code usage and countless hours of trial and error, I've developed a rule-based system that transformed my AI-assisted development workflow. Here's everything I learned.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem: AI That Forgets Everything
&lt;/h2&gt;

&lt;p&gt;When I first started using Claude Code for building Angular applications, I was excited. An AI that could write code, understand context, and help me build faster? Sign me up.&lt;/p&gt;

&lt;p&gt;But reality hit quickly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The AI kept making the same mistakes.&lt;/strong&gt; It would use &lt;code&gt;bg-[var(--bg-primary)]&lt;/code&gt; instead of proper Tailwind semantic classes. It forgot to implement dark mode. It used constructor injection when I needed &lt;code&gt;inject()&lt;/code&gt;. Every. Single. Time.&lt;/p&gt;

&lt;p&gt;I found myself copy-pasting the same corrections over and over:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"No, use &lt;code&gt;bg-card&lt;/code&gt; not &lt;code&gt;bg-[var(--card)]&lt;/code&gt;"&lt;br&gt;
"Remember, we're using Angular v21 signals, not the old syntax"&lt;br&gt;
"Don't forget dark mode support"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;I was spending more time correcting the AI than coding.&lt;/strong&gt;&lt;/p&gt;

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

&lt;p&gt;After 6 months of refining my approach, I've built a system that eliminates 90% of these corrections. Claude Code now produces consistent, production-ready code on the first try.&lt;/p&gt;

&lt;p&gt;Here's exactly how I did it.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Solution: A Structured Rule System
&lt;/h2&gt;

&lt;p&gt;The key insight was simple: &lt;strong&gt;Claude Code can't remember your preferences between sessions, but it CAN read files at the start of every conversation.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Instead of repeating myself, I created a &lt;code&gt;.claude/&lt;/code&gt; directory with structured rule files that Claude reads automatically. Think of it as giving your AI assistant a comprehensive onboarding document.&lt;/p&gt;

&lt;h3&gt;
  
  
  My File Structure
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.claude/
├── CLAUDE.md                  # Main project memory &amp;amp; quick reference
├── README.md                  # Overview of all rules
├── TODO-TEMPLATE.md           # Template for tracking progress
└── rules/
    ├── accessibility.md       # WCAG AA requirements
    ├── ai-components.md       # AI chat component patterns
    ├── angular-cdk.md         # Angular CDK usage
    ├── angular-v21.md         # Angular v21 best practices
    ├── architecture.md        # Scalability patterns
    ├── component-patterns.md  # Component structure
    ├── styling-architecture.md # CSS variables &amp;amp; theming
    ├── tailwind-v4.md         # Tailwind v4 setup
    ├── todo-management.md     # Progress tracking
    └── typescript.md          # TypeScript patterns
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why split into multiple files?&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Easier maintenance&lt;/strong&gt; - Update one concern without touching others&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Better organization&lt;/strong&gt; - Find rules quickly when you need to reference them&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Modular loading&lt;/strong&gt; - Claude can focus on relevant rules for specific tasks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cleaner diffs&lt;/strong&gt; - Git history shows exactly what changed and why&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Tip #1: Add Rules When AI Keeps Repeating Mistakes
&lt;/h2&gt;

&lt;p&gt;This is the most valuable habit I've developed: &lt;strong&gt;Every time Claude makes the same mistake twice, I add a rule.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Real Example: The Dark Mode Disaster
&lt;/h3&gt;

&lt;p&gt;Claude kept generating Tailwind classes like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- What Claude kept generating --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or worse:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- The CSS variable nightmare --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"bg-[var(--card)] text-[var(--foreground)]"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both approaches are maintenance nightmares. The first requires duplicating every color with &lt;code&gt;dark:&lt;/code&gt; prefixes. The second bypasses Tailwind's utility system entirely.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix?&lt;/strong&gt; I added this to my &lt;code&gt;styling-architecture.md&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## ❌ What NOT to Do&lt;/span&gt;

&lt;span class="gu"&gt;### NEVER Use dark: Prefix&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;br&gt;
// ❌ WRONG: dark: prefix&lt;br&gt;
'bg-white dark:bg-gray-900'&lt;br&gt;
'text-gray-900 dark:text-gray-100'&lt;/p&gt;

&lt;p&gt;// ✅ CORRECT: Tailwind semantic classes&lt;br&gt;
'bg-card'&lt;br&gt;
'text-foreground'&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
### NEVER Use var() in Tailwind Classes

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;br&gt;
// ❌ WRONG: var() syntax&lt;br&gt;
'bg-[var(--card)]'&lt;br&gt;
'text-[var(--foreground)]'&lt;/p&gt;

&lt;p&gt;// ✅ CORRECT: Tailwind semantic classes&lt;br&gt;
'bg-card'&lt;br&gt;
'text-foreground'&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt; Claude now automatically uses the correct pattern. No more corrections needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Rule-Adding Workflow
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Notice a repeated mistake&lt;/strong&gt; - Claude does something wrong twice&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Identify the correct pattern&lt;/strong&gt; - What should it have done?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write a clear rule&lt;/strong&gt; - Include both ❌ wrong and ✅ correct examples&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add to the appropriate file&lt;/strong&gt; - Put it where it logically belongs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test&lt;/strong&gt; - Verify Claude follows the rule in your next session&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Tip #2: Structure Rules with Clear Examples
&lt;/h2&gt;

&lt;p&gt;Vague rules don't work. "Use proper styling" means nothing. &lt;strong&gt;Concrete examples are everything.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here's my template for effective rules:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## [Pattern Name]&lt;/span&gt;

&lt;span class="gs"&gt;**When to use:**&lt;/span&gt; [Clear trigger condition]

&lt;span class="gu"&gt;### ✅ Correct&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;br&gt;
// Good: Explanation of why this is right&lt;br&gt;
const example = 'correct pattern';&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
### ❌ Wrong

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;br&gt;
// Bad: Explanation of why this is wrong&lt;br&gt;
const example = 'incorrect pattern';&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
### Why This Matters

[1-2 sentences explaining the reasoning]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Real Example from My Component Patterns
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Template Files (CRITICAL)&lt;/span&gt;

&lt;span class="gs"&gt;**ALWAYS use separate HTML template files for components. DO NOT use inline templates.**&lt;/span&gt;

&lt;span class="gu"&gt;### ✅ CORRECT: Use separate template file&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;br&gt;
@Component({&lt;br&gt;
  selector: 'ai-message-bubble',&lt;br&gt;
  templateUrl: './message-bubble.component.html',&lt;br&gt;
  changeDetection: ChangeDetectionStrategy.OnPush,&lt;br&gt;
})&lt;br&gt;
export class MessageBubbleComponent {}&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
### ❌ WRONG: Inline template

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;br&gt;
@Component({&lt;br&gt;
  selector: 'ai-message-bubble',&lt;br&gt;
  template: &lt;code&gt;...&lt;/code&gt;,&lt;br&gt;
})&lt;br&gt;
export class MessageBubbleComponent {}&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
### Why Separate Templates?

- Better IDE support (syntax highlighting, Emmet)
- Cleaner component files
- Easier code reviews
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The explicit ✅ and ❌ markers make it crystal clear what Claude should and shouldn't do.&lt;/p&gt;




&lt;h2&gt;
  
  
  Tip #3: Create a Central Quick Reference (CLAUDE.md)
&lt;/h2&gt;

&lt;p&gt;While split files are great for detailed rules, you need a central document for critical reminders. My &lt;code&gt;CLAUDE.md&lt;/code&gt; serves as the "executive summary."&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Sections in My CLAUDE.md
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. Project Overview&lt;/strong&gt; - What we're building&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Project Overview&lt;/span&gt;

This is an &lt;span class="gs"&gt;**Angular v21**&lt;/span&gt; component library focused on AI chat interfaces.
We're building standalone, signal-first components with &lt;span class="gs"&gt;**Tailwind CSS v4**&lt;/span&gt; styling.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. What NOT to Do&lt;/strong&gt; - The most common mistakes&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Quick Reference: What NOT to Do&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; ❌ Don't use NgModules (use standalone components)
&lt;span class="p"&gt;-&lt;/span&gt; ❌ Don't set &lt;span class="sb"&gt;`standalone: true`&lt;/span&gt; (it's default in Angular v20+)
&lt;span class="p"&gt;-&lt;/span&gt; ❌ Don't use &lt;span class="sb"&gt;`@HostBinding`&lt;/span&gt;/&lt;span class="sb"&gt;`@HostListener`&lt;/span&gt; (use &lt;span class="sb"&gt;`host`&lt;/span&gt; object)
&lt;span class="p"&gt;-&lt;/span&gt; ❌ Don't use constructor injection (use &lt;span class="sb"&gt;`inject()`&lt;/span&gt; function)
&lt;span class="p"&gt;-&lt;/span&gt; ❌ &lt;span class="gs"&gt;**NEVER use `dark:` prefix**&lt;/span&gt; (use semantic classes)
&lt;span class="p"&gt;-&lt;/span&gt; ❌ &lt;span class="gs"&gt;**NEVER use `var()` in Tailwind**&lt;/span&gt; (use bg-card NOT bg-[var(--card)])
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Rule File Index&lt;/strong&gt; - Where to find detailed rules&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Rule Files&lt;/span&gt;

| File                      | Purpose                                    |
| ------------------------- | ------------------------------------------ |
| &lt;span class="sb"&gt;`accessibility.md`&lt;/span&gt;        | WCAG, ARIA, keyboard navigation            |
| &lt;span class="sb"&gt;`angular-v21.md`&lt;/span&gt;          | Angular patterns, signals, standalone      |
| &lt;span class="sb"&gt;`styling-architecture.md`&lt;/span&gt; | CSS variables, color system, dark mode     |
| &lt;span class="sb"&gt;`tailwind-v4.md`&lt;/span&gt;          | Tailwind v4 setup, cn() utility            |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4. Code Review Checklist&lt;/strong&gt; - Quality gates&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Code Review Checklist&lt;/span&gt;

Before considering code complete:

&lt;span class="gs"&gt;**Structure:**&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Separate HTML template file (not inline)
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Barrel export (&lt;span class="sb"&gt;`index.ts`&lt;/span&gt;) in folder
&lt;span class="p"&gt;-&lt;/span&gt; [ ] OnPush change detection
&lt;span class="p"&gt;-&lt;/span&gt; [ ] ViewEncapsulation.None

&lt;span class="gs"&gt;**Styling:**&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; [ ] CSS only (no SCSS)
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Tailwind utility classes
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Dark mode support
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Tip #4: Track Progress with TODO Files
&lt;/h2&gt;

&lt;p&gt;For large features or multi-session projects, Claude needs to know what's done and what's left. I use a TODO system that persists across sessions.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Problem with Large Projects
&lt;/h3&gt;

&lt;p&gt;When building something complex—like a 15-component library—Claude can lose track:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What components are finished?&lt;/li&gt;
&lt;li&gt;What's currently being worked on?&lt;/li&gt;
&lt;li&gt;What's the priority order?&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  My Solution: Phase-Based TODOs
&lt;/h3&gt;

&lt;p&gt;I create a &lt;code&gt;TODO.md&lt;/code&gt; at the start of each phase:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Phase 0.2 - Core Chat Components&lt;/span&gt;

&lt;span class="gu"&gt;## ✅ Completed Tasks&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; [x] MessageBubble component
&lt;span class="p"&gt;-&lt;/span&gt; [x] MessageList component
&lt;span class="p"&gt;-&lt;/span&gt; [x] Dark mode support

&lt;span class="gu"&gt;## 🔄 In Progress&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; [ ] ChatInput component (currently implementing)
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Auto-resize textarea

&lt;span class="gu"&gt;## 📋 Pending&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; [ ] TypingIndicator component
&lt;span class="p"&gt;-&lt;/span&gt; [ ] StreamingText component

&lt;span class="gu"&gt;## 📊 Progress Summary&lt;/span&gt;

&lt;span class="gs"&gt;**Overall Progress:**&lt;/span&gt; 40% Complete
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Workflow
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Start of phase:&lt;/strong&gt; Create TODO from template&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;During work:&lt;/strong&gt; Mark tasks &lt;code&gt;[x]&lt;/code&gt; immediately after completion&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;End of session:&lt;/strong&gt; Update progress summary&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;End of phase:&lt;/strong&gt; Archive as &lt;code&gt;TODO-Phase-0.2.md&lt;/code&gt;, create fresh TODO for next phase&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This gives Claude instant context on project status, even in a brand new session.&lt;/p&gt;




&lt;h2&gt;
  
  
  Tip #5: Use Path-Specific Rules
&lt;/h2&gt;

&lt;p&gt;Some rules only apply to certain files. Claude's rule system supports this with frontmatter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;**/*.component.ts'&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="gh"&gt;# Component Structure &amp;amp; Patterns&lt;/span&gt;

These rules apply specifically to Angular components...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This tells Claude to apply these rules when working on component files, but not when editing services or utilities.&lt;/p&gt;

&lt;h3&gt;
  
  
  My Path-Specific Rules
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;File&lt;/th&gt;
&lt;th&gt;Paths&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;component-patterns.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;**/*.component.ts&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Component structure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;typescript.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;**/*.ts&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;TypeScript patterns&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;accessibility.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;**/*.{ts,component.ts}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A11y requirements&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tailwind-v4.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;**/*.{ts,css}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Styling rules&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Tip #6: Document the "Why," Not Just the "What"
&lt;/h2&gt;

&lt;p&gt;Rules work better when Claude understands the reasoning. Compare these:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Weak rule:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;Use &lt;span class="sb"&gt;`inject()`&lt;/span&gt; instead of constructor injection.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Strong rule:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Service Injection&lt;/span&gt;

Use &lt;span class="sb"&gt;`inject()`&lt;/span&gt; function instead of constructor injection.

&lt;span class="gu"&gt;### Why?&lt;/span&gt;
&lt;span class="p"&gt;
1.&lt;/span&gt; Works with standalone components without module context
&lt;span class="p"&gt;2.&lt;/span&gt; Cleaner syntax with less boilerplate
&lt;span class="p"&gt;3.&lt;/span&gt; Better tree-shaking support
&lt;span class="p"&gt;4.&lt;/span&gt; Consistent with Angular's modern patterns

&lt;span class="gu"&gt;### ✅ Correct&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;br&gt;
export class ChatComponent {&lt;br&gt;
  private chatService = inject(ChatService);&lt;br&gt;
  private config = inject(CHAT_CONFIG);&lt;br&gt;
}&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
### ❌ Wrong

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;br&gt;
export class ChatComponent {&lt;br&gt;
  constructor(private chatService: ChatService) {}&lt;br&gt;
}&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When Claude understands &lt;em&gt;why&lt;/em&gt; a pattern exists, it makes better decisions in edge cases.&lt;/p&gt;




&lt;h2&gt;
  
  
  Tip #7: Include Technology Version Context
&lt;/h2&gt;

&lt;p&gt;AI models often default to older patterns. Be explicit about versions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Critical Context&lt;/span&gt;

&lt;span class="gs"&gt;**CRITICAL: We are using Angular v21 and Tailwind CSS v4**&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Angular v21 is the LATEST version with all modern features
&lt;span class="p"&gt;-&lt;/span&gt; Tailwind v4 uses NEW @tailwindcss/postcss plugin (not the old tailwindcss plugin)
&lt;span class="p"&gt;-&lt;/span&gt; AI assistants often make mistakes with latest versions - ALWAYS verify against official docs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This primes Claude to use modern patterns instead of falling back to outdated approaches.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Results: Before vs. After
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Before (Without Rule System)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Constant corrections needed&lt;/li&gt;
&lt;li&gt;Inconsistent code patterns&lt;/li&gt;
&lt;li&gt;Had to review everything manually&lt;/li&gt;
&lt;li&gt;Repeated prompts for same issues&lt;/li&gt;
&lt;li&gt;Development felt slow and frustrating&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  After (With Rule System)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;90% fewer corrections&lt;/li&gt;
&lt;li&gt;Consistent, production-ready code&lt;/li&gt;
&lt;li&gt;Trust the output, verify less&lt;/li&gt;
&lt;li&gt;Never repeat the same instruction&lt;/li&gt;
&lt;li&gt;Development feels 10x faster&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The initial investment of creating these rule files paid for itself within days.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Getting Started: Your First Rule File
&lt;/h2&gt;

&lt;p&gt;Don't try to build my entire system on day one. Start small:&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Create &lt;code&gt;.claude/CLAUDE.md&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Add your tech stack and 3-5 "What NOT to Do" items:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Project Memory&lt;/span&gt;

&lt;span class="gu"&gt;## Tech Stack&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; [Your framework] v[version]
&lt;span class="p"&gt;-&lt;/span&gt; [Your CSS solution]

&lt;span class="gu"&gt;## What NOT to Do&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; ❌ [Most common mistake]
&lt;span class="p"&gt;-&lt;/span&gt; ❌ [Second most common mistake]
&lt;span class="p"&gt;-&lt;/span&gt; ❌ [Third most common mistake]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Add Rules When Mistakes Repeat
&lt;/h3&gt;

&lt;p&gt;Every time you correct Claude twice for the same thing:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a rule file in &lt;code&gt;.claude/rules/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Document the correct pattern with examples&lt;/li&gt;
&lt;li&gt;Add a reference in &lt;code&gt;CLAUDE.md&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Step 3: Review and Refine Weekly
&lt;/h3&gt;

&lt;p&gt;As your rule files grow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Split large files into focused topics&lt;/li&gt;
&lt;li&gt;Remove rules that are no longer relevant&lt;/li&gt;
&lt;li&gt;Add new rules for new patterns&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Quick Reference: Rule File Best Practices
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Do&lt;/th&gt;
&lt;th&gt;Don't&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;✅ Use concrete examples&lt;/td&gt;
&lt;td&gt;❌ Write vague guidelines&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;✅ Show ❌ wrong AND ✅ correct&lt;/td&gt;
&lt;td&gt;❌ Only show correct patterns&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;✅ Explain the "why"&lt;/td&gt;
&lt;td&gt;❌ Give rules without reasoning&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;✅ Keep files focused (one topic each)&lt;/td&gt;
&lt;td&gt;❌ Dump everything in one file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;✅ Update rules when AI makes new mistakes&lt;/td&gt;
&lt;td&gt;❌ Let outdated rules accumulate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;✅ Include version numbers&lt;/td&gt;
&lt;td&gt;❌ Assume AI knows your tech stack&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




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

&lt;p&gt;Claude Code is an incredible tool, but it's only as good as the context you provide. By building a structured rule system:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;You eliminate repetitive corrections&lt;/strong&gt; - Rules persist across sessions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You get consistent output&lt;/strong&gt; - Same patterns every time&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You build faster&lt;/strong&gt; - Less review, more shipping&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You create institutional knowledge&lt;/strong&gt; - Rules document your project's standards&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The investment in creating rule files pays dividends on every single Claude Code session.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Start with one file. Add rules when mistakes repeat. Split files as they grow.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's it. That's the system.&lt;/p&gt;




&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/hassantayyab" rel="noopener noreferrer"&gt;My GitHub&lt;/a&gt; - See my projects using this approach&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.anthropic.com/en/docs/claude-code" rel="noopener noreferrer"&gt;Claude Code Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hassantayyab.com/blogs" rel="noopener noreferrer"&gt;More articles on my blog&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Have questions about this approach? Connect with me on &lt;a href="https://www.linkedin.com/in/hassan-t-dogar/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; or &lt;a href="https://x.com/htdogar" rel="noopener noreferrer"&gt;X/Twitter&lt;/a&gt;. I'd love to hear how you're using Claude Code in your workflow.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Keywords:&lt;/strong&gt; Claude Code, AI-assisted development, Claude Code tips, AI coding assistant, Claude rules, developer productivity, Angular development, Tailwind CSS, AI pair programming, Claude Code workflow, AI coding best practices, development automation&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>productivity</category>
      <category>claudecode</category>
    </item>
    <item>
      <title>🚀 Prompt Engineering: A Practical Guide for Developers</title>
      <dc:creator>hassantayyab</dc:creator>
      <pubDate>Fri, 12 Dec 2025 14:48:49 +0000</pubDate>
      <link>https://dev.to/hassantayyab/prompt-engineering-a-practical-guide-for-developers-33c3</link>
      <guid>https://dev.to/hassantayyab/prompt-engineering-a-practical-guide-for-developers-33c3</guid>
      <description>&lt;p&gt;Prompt engineering is the practice of designing inputs that reliably guide large language models to produce &lt;strong&gt;accurate, structured, and useful outputs&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For developers, prompt engineering is not about clever wording.&lt;br&gt;
It is about &lt;strong&gt;controlling ambiguity&lt;/strong&gt;, &lt;strong&gt;constraining solutions&lt;/strong&gt;, and &lt;strong&gt;shaping reasoning&lt;/strong&gt; so the model produces correct code.&lt;/p&gt;

&lt;p&gt;This guide covers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the &lt;strong&gt;core prompt engineering techniques&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;why they exist&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;when to use each&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;how they apply to real coding workflows&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  What Is Prompt Engineering?
&lt;/h2&gt;

&lt;p&gt;Prompt engineering is the process of turning an intent into a precise instruction that a model can execute correctly.&lt;/p&gt;

&lt;p&gt;In software development, this includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;generating code&lt;/li&gt;
&lt;li&gt;refactoring safely&lt;/li&gt;
&lt;li&gt;debugging errors&lt;/li&gt;
&lt;li&gt;enforcing style and structure&lt;/li&gt;
&lt;li&gt;producing machine-readable outputs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can think of prompts as &lt;strong&gt;specifications&lt;/strong&gt;.&lt;br&gt;
Poor specifications produce poor implementations.&lt;/p&gt;


&lt;h2&gt;
  
  
  Core Prompt Engineering Techniques
&lt;/h2&gt;

&lt;p&gt;Below are the &lt;strong&gt;standard techniques&lt;/strong&gt; used in prompt engineering, explained in a practical, developer-friendly way.&lt;/p&gt;


&lt;h2&gt;
  
  
  1. Zero-Shot Prompting
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt;&lt;br&gt;
Asking the model to perform a task without giving examples.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&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;Write a function that removes duplicate values from an array while preserving order.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;When to use it:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Common tasks&lt;/li&gt;
&lt;li&gt;Well-defined problems&lt;/li&gt;
&lt;li&gt;Straightforward code generation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Limitations:&lt;/strong&gt;&lt;br&gt;
Fails when format, style, or edge cases matter.&lt;/p&gt;


&lt;h2&gt;
  
  
  2. Few-Shot Prompting
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt;&lt;br&gt;
Providing one or more examples to demonstrate the desired pattern.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&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;Convert text to snake_case.

Input: "User Name"
Output: "user_name"

Input: "Account ID"
Output: "account_id"

Now convert: "Order Number"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;When to use it:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Output formatting matters&lt;/li&gt;
&lt;li&gt;Naming conventions&lt;/li&gt;
&lt;li&gt;Transformations and parsing&lt;/li&gt;
&lt;li&gt;UI or data normalization&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Few-shot prompting dramatically improves consistency.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Instruction Prompting
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt;&lt;br&gt;
Explicitly telling the model what to do.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&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;Refactor this code for readability.
Do not change behavior.
Remove dead code.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt;&lt;br&gt;
Models follow instructions better than vague descriptions.&lt;/p&gt;


&lt;h2&gt;
  
  
  4. Contextual Prompting
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt;&lt;br&gt;
Providing background information that shapes decisions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&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;This code is part of a TypeScript backend.
The project enforces immutability and strict typing.
Refactor the function accordingly.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;When to use it:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Existing codebases&lt;/li&gt;
&lt;li&gt;Architectural constraints&lt;/li&gt;
&lt;li&gt;Style enforcement&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Context reduces incorrect assumptions.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Role Prompting
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt;&lt;br&gt;
Assigning the model a role to bias decision-making.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&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;Act as a senior software engineer.
Review the following code and suggest improvements.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why it works:&lt;/strong&gt;&lt;br&gt;
Different roles imply different trade-offs (performance, safety, readability).&lt;/p&gt;


&lt;h2&gt;
  
  
  6. Chain-of-Thought Prompting
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt;&lt;br&gt;
Asking the model to reason step-by-step before answering.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&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;Analyze the problem step-by-step.
Explain the root cause.
Then provide the corrected code.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Best used for:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Debugging&lt;/li&gt;
&lt;li&gt;Algorithms&lt;/li&gt;
&lt;li&gt;Complex logic&lt;/li&gt;
&lt;li&gt;Data processing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This improves correctness and transparency.&lt;/p&gt;




&lt;h2&gt;
  
  
  7. Delimiter Prompting
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt;&lt;br&gt;
Separating instructions from code or data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&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;Analyze the following code and identify bugs:

[code]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt;&lt;br&gt;
Prevents the model from mixing instructions with content.&lt;/p&gt;


&lt;h2&gt;
  
  
  8. Structured Output Prompting
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt;&lt;br&gt;
Explicitly defining the output format.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&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;Return the result in this format:

{
  "summary": "...",
  "issues": [],
  "fixed_code": "..."
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Essential for:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Automation&lt;/li&gt;
&lt;li&gt;Tooling&lt;/li&gt;
&lt;li&gt;Programmatic consumption&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  9. Constraint Prompting
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt;&lt;br&gt;
Defining hard rules the solution must follow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&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;Rewrite this function with these constraints:
- No external libraries
- Time complexity must be O(n)
- Do not change the public API
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Constraints dramatically reduce bad solutions.&lt;/p&gt;




&lt;h2&gt;
  
  
  10. Error-Driven Prompting
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt;&lt;br&gt;
Using real error messages as input.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&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;Here is the exact error and stack trace:
[error]

Explain the root cause and provide a fix.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why it works:&lt;/strong&gt;&lt;br&gt;
Error messages anchor the model to reality.&lt;/p&gt;


&lt;h2&gt;
  
  
  11. Self-Reflection Prompting
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt;&lt;br&gt;
Asking the model to review and correct itself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&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;Review your previous answer.
Identify edge cases and improve the solution.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This often catches subtle bugs.&lt;/p&gt;




&lt;h2&gt;
  
  
  12. Prompt Chaining
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt;&lt;br&gt;
Breaking a complex task into multiple prompts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example workflow:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Analyze requirements&lt;/li&gt;
&lt;li&gt;Define interfaces&lt;/li&gt;
&lt;li&gt;Implement logic&lt;/li&gt;
&lt;li&gt;Add validation&lt;/li&gt;
&lt;li&gt;Write tests&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Each step has a focused prompt.&lt;/p&gt;




&lt;h2&gt;
  
  
  Coding-Focused Use Cases
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Code Generation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Write a reusable debounce utility.
Handle edge cases and explain the logic.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Refactoring
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Refactor this code for readability without changing behavior.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Debugging
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Explain why this function fails for negative values and fix it.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Performance Optimization
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Analyze time and space complexity.
Optimize the function and explain the changes.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Documentation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Generate documentation with usage examples for this module.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Best Practices
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Be explicit&lt;/li&gt;
&lt;li&gt;Provide context when needed&lt;/li&gt;
&lt;li&gt;Use examples when format matters&lt;/li&gt;
&lt;li&gt;Define output structure&lt;/li&gt;
&lt;li&gt;Add constraints early&lt;/li&gt;
&lt;li&gt;Use step-by-step reasoning for complex tasks&lt;/li&gt;
&lt;li&gt;Break large problems into smaller prompts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Prompt engineering is iterative, like coding.&lt;/p&gt;




&lt;h2&gt;
  
  
  Prompt Engineering Cheat Sheet
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Techniques
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Technique&lt;/th&gt;
&lt;th&gt;When to Use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Zero-shot&lt;/td&gt;
&lt;td&gt;Simple, common tasks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Few-shot&lt;/td&gt;
&lt;td&gt;Formatting, transformations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Instruction prompting&lt;/td&gt;
&lt;td&gt;Direct actions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Contextual prompting&lt;/td&gt;
&lt;td&gt;Codebase consistency&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Role prompting&lt;/td&gt;
&lt;td&gt;Quality and trade-offs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Chain-of-thought&lt;/td&gt;
&lt;td&gt;Logic and debugging&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Structured output&lt;/td&gt;
&lt;td&gt;Automation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Constraint prompting&lt;/td&gt;
&lt;td&gt;Safety and correctness&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Error-driven prompting&lt;/td&gt;
&lt;td&gt;Debugging&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Prompt chaining&lt;/td&gt;
&lt;td&gt;Large workflows&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Common Coding Tasks
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Task&lt;/th&gt;
&lt;th&gt;Example Prompt&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Generate code&lt;/td&gt;
&lt;td&gt;“Write a function that…”&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Refactor&lt;/td&gt;
&lt;td&gt;“Improve readability without changing behavior.”&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Debug&lt;/td&gt;
&lt;td&gt;“Explain and fix this error.”&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Optimize&lt;/td&gt;
&lt;td&gt;“Reduce time complexity.”&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Document&lt;/td&gt;
&lt;td&gt;“Add documentation with examples.”&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Review&lt;/td&gt;
&lt;td&gt;“Review and suggest improvements.”&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Final Thought
&lt;/h2&gt;

&lt;p&gt;Prompt engineering is not about talking to AI.&lt;br&gt;
It is about &lt;strong&gt;designing instructions&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The better your prompts, the more predictable and useful the output becomes.&lt;/p&gt;

&lt;p&gt;Treat prompts like code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;structured&lt;/li&gt;
&lt;li&gt;constrained&lt;/li&gt;
&lt;li&gt;reviewed&lt;/li&gt;
&lt;li&gt;improved over time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s how AI becomes a real development tool.&lt;/p&gt;

</description>
      <category>promptengineering</category>
      <category>programming</category>
      <category>ai</category>
      <category>frontend</category>
    </item>
    <item>
      <title>A Beginner Friendly Guide to Memoization in NgRx Selectors</title>
      <dc:creator>hassantayyab</dc:creator>
      <pubDate>Fri, 28 Nov 2025 12:24:53 +0000</pubDate>
      <link>https://dev.to/hassantayyab/a-beginner-friendly-guide-to-memoization-in-ngrx-selectors-1ll2</link>
      <guid>https://dev.to/hassantayyab/a-beginner-friendly-guide-to-memoization-in-ngrx-selectors-1ll2</guid>
      <description>&lt;p&gt;&lt;strong&gt;Memoization&lt;/strong&gt; is a way to speed up functions by &lt;strong&gt;caching their results&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you call a function with the &lt;strong&gt;same inputs&lt;/strong&gt;, instead of recomputing everything again, it just returns the &lt;strong&gt;previous result from memory&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Very simplified:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;memoize&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="nf"&gt;extends &lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kr"&gt;any&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;fn&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="nx"&gt;T&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;lastArgs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&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;let&lt;/span&gt; &lt;span class="nx"&gt;lastResult&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&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;lastArgs&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
      &lt;span class="nx"&gt;args&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;lastArgs&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;amp;&amp;amp;&lt;/span&gt;
      &lt;span class="nx"&gt;args&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;arg&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;arg&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;lastArgs&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="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="nx"&gt;lastResult&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// same inputs -&amp;gt; reuse result&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;lastArgs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;lastResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;lastResult&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;T&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;So:&lt;br&gt;
Same args → skip work → return cached result.&lt;/p&gt;


&lt;h2&gt;
  
  
  Why memoization matters in NgRx
&lt;/h2&gt;

&lt;p&gt;In NgRx you often have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A big &lt;strong&gt;state tree&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Selectors&lt;/strong&gt; that derive data from that state&lt;/li&gt;
&lt;li&gt;Components that subscribe to those selectors&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some derived data can be &lt;strong&gt;expensive&lt;/strong&gt; to compute:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Filtering large lists&lt;/li&gt;
&lt;li&gt;Sorting&lt;/li&gt;
&lt;li&gt;Computing aggregates&lt;/li&gt;
&lt;li&gt;Mapping to complex view models&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your selector recalculates this on &lt;strong&gt;every change detection&lt;/strong&gt;, your app feels heavier than it should.&lt;/p&gt;

&lt;p&gt;This is where NgRx comes in with a gift:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Selectors created with &lt;code&gt;createSelector&lt;/code&gt; are memoized by default.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;They only recompute when &lt;strong&gt;their inputs change&lt;/strong&gt; (by reference).&lt;/p&gt;


&lt;h2&gt;
  
  
  Basic NgRx selector example (with memoization)
&lt;/h2&gt;

&lt;p&gt;Imagine a simple state:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Todo&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;TodosState&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Todo&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="nl"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;all&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;completed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;active&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Feature selector:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;selectTodosState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createFeatureSelector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;TodosState&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;todos&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;Now a few selectors:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;selectTodos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createSelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;selectTodosState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;selectFilter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createSelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;selectTodosState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;selectFilteredTodos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createSelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;selectTodos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;selectFilter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;filter&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="s1"&gt;Recomputing filtered todos...&lt;/span&gt;&lt;span class="dl"&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;filter&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;completed&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;todos&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;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="nx"&gt;completed&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;filter&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;active&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;todos&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;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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completed&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="nx"&gt;todos&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;What NgRx does for you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;selectFilteredTodos&lt;/code&gt; is &lt;strong&gt;memoized&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;It only recalculates when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;selectTodos&lt;/code&gt; returns a &lt;strong&gt;new array reference&lt;/strong&gt;, or&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;selectFilter&lt;/code&gt; returns a &lt;strong&gt;new filter value&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;If &lt;strong&gt;unrelated&lt;/strong&gt; parts of the store change, and the &lt;code&gt;todos&lt;/code&gt; array and &lt;code&gt;filter&lt;/code&gt; are the same references, NgRx just returns the &lt;strong&gt;cached filtered list&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Less CPU, fewer unnecessary component updates.&lt;/p&gt;




&lt;h2&gt;
  
  
  How this helps your Angular components
&lt;/h2&gt;

&lt;p&gt;Component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-todos&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
    &amp;lt;div *ngFor="let todo of todos$ | async"&amp;gt;
      {{ todo.title }}
    &amp;lt;/div&amp;gt;
  `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;changeDetection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ChangeDetectionStrategy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OnPush&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TodosComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;todos$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;selectFilteredTodos&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Store&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;Because &lt;code&gt;selectFilteredTodos&lt;/code&gt; is memoized:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;If state changes &lt;strong&gt;somewhere else&lt;/strong&gt; (e.g. user profile), but todos slice is unchanged:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Selector returns the &lt;strong&gt;same array reference&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;With OnPush, Angular sees no new value → no re-render of this list&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;This is exactly the combo you want:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;NgRx memoization&lt;/li&gt;
&lt;li&gt;OnPush change detection&lt;/li&gt;
&lt;li&gt;Less work, smoother app&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Memoization and selectors with props
&lt;/h2&gt;

&lt;p&gt;You can also use memoization when your selector depends on &lt;strong&gt;an argument&lt;/strong&gt;, for example selecting a single todo by id.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;selectTodoById&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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;createSelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;selectTodos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todos&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="s1"&gt;Recomputing todo by id...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&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="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="kc"&gt;null&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;Then in your component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;todo$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;selectTodoById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;todoId&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;NgRx memoizes &lt;strong&gt;per selector instance&lt;/strong&gt; here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For this particular &lt;code&gt;id&lt;/code&gt;, as long as &lt;code&gt;selectTodos&lt;/code&gt; returns the same array reference, the selector returns the &lt;strong&gt;cached todo&lt;/strong&gt; and doesn’t run &lt;code&gt;find&lt;/code&gt; again.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  A subtle gotcha: new objects break memoization
&lt;/h2&gt;

&lt;p&gt;Memoization in NgRx works based on &lt;strong&gt;referential equality&lt;/strong&gt; of the selector inputs.&lt;/p&gt;

&lt;p&gt;If you do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;selectTodoViewModels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createSelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;selectTodos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todos&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;todos&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="p"&gt;({&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="na"&gt;label&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="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completed&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&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="s1"&gt;⬜&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="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="nx"&gt;title&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="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;Each time &lt;code&gt;selectTodoViewModels&lt;/code&gt; recomputes, it returns a &lt;strong&gt;new array with new objects&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The selector itself is still memoized, but if &lt;strong&gt;&lt;code&gt;todos&lt;/code&gt; changes reference often&lt;/strong&gt;, you’re rebuilding everything.&lt;/p&gt;

&lt;p&gt;Better pattern in many cases:&lt;br&gt;
Keep heavy transformations inside &lt;strong&gt;selectors&lt;/strong&gt;, but don’t unnecessarily create new objects if inputs haven’t changed. Memoization helps at the selector level, but your code still needs to be reasonable.&lt;/p&gt;




&lt;h2&gt;
  
  
  Custom memoization (if you ever need more control)
&lt;/h2&gt;

&lt;p&gt;NgRx also lets you define selectors with custom memoization via &lt;code&gt;createSelectorFactory&lt;/code&gt;, but honestly in most apps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;createSelector&lt;/code&gt;’s built-in memoization is enough&lt;/li&gt;
&lt;li&gt;You rarely need to touch lower-level memoization&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you ever have a crazy use case with complex arguments, that’s when you look into selector factories.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick recap
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Memoization&lt;/strong&gt; = caching function results based on inputs&lt;/li&gt;
&lt;li&gt;NgRx &lt;strong&gt;selectors created with &lt;code&gt;createSelector&lt;/code&gt; are memoized by default&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;They recompute only when their &lt;strong&gt;input selectors’ outputs change by reference&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;This works beautifully with &lt;strong&gt;OnPush&lt;/strong&gt; and large apps where you can’t afford to recompute everything on every change detection&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use selectors to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Filter, sort, and derive data&lt;/li&gt;
&lt;li&gt;Keep components lean&lt;/li&gt;
&lt;li&gt;Let memoization + change detection handle performance&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

</description>
      <category>programming</category>
      <category>webdev</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Angular Aria vs Angular Primitives: What’s the Difference and When Should You Use Each?</title>
      <dc:creator>hassantayyab</dc:creator>
      <pubDate>Thu, 27 Nov 2025 12:38:24 +0000</pubDate>
      <link>https://dev.to/hassantayyab/angular-aria-vs-angular-primitives-whats-the-difference-and-when-should-you-use-each-5f1</link>
      <guid>https://dev.to/hassantayyab/angular-aria-vs-angular-primitives-whats-the-difference-and-when-should-you-use-each-5f1</guid>
      <description>&lt;h1&gt;
  
  
  Angular Aria vs Angular Primitives: What’s the Difference and When Should You Use Each?
&lt;/h1&gt;

&lt;p&gt;The Angular ecosystem is evolving rapidly, especially around &lt;em&gt;headless UI&lt;/em&gt;, accessibility, and composable component design. Two major players in this space are &lt;strong&gt;Angular Aria&lt;/strong&gt; (introduced officially in Angular 21) and the &lt;strong&gt;Angular Primitives&lt;/strong&gt; community library.&lt;/p&gt;

&lt;p&gt;At first glance they may seem similar — both provide unstyled, headless building blocks for creating highly customizable UI components. But they actually solve &lt;em&gt;different layers&lt;/em&gt; of the UI problem.&lt;/p&gt;

&lt;p&gt;Understanding how they differ, where they overlap, and how to use them together is key if you’re building modern Angular applications, design systems, or complex custom UI libraries.&lt;/p&gt;

&lt;p&gt;This article breaks it all down.&lt;/p&gt;




&lt;h1&gt;
  
  
  What Is Angular Aria?
&lt;/h1&gt;

&lt;p&gt;Angular Aria is an &lt;strong&gt;official Angular package&lt;/strong&gt; introduced in Angular 21. Its goal is simple:&lt;br&gt;
to make accessible components easy to build.&lt;/p&gt;

&lt;p&gt;Angular Aria provides &lt;strong&gt;WAI-ARIA–compliant UI patterns&lt;/strong&gt; that include baked-in accessibility behaviors such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keyboard navigation&lt;/li&gt;
&lt;li&gt;Focus management&lt;/li&gt;
&lt;li&gt;Screen-reader semantics&lt;/li&gt;
&lt;li&gt;ARIA roles and state attributes&lt;/li&gt;
&lt;li&gt;Correct interactive behavior patterns (accordion, tabs, tree, grid, etc.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These components are &lt;strong&gt;headless&lt;/strong&gt; — meaning they come with no CSS or styling. You provide all the UI design, and Angular Aria provides the accessibility and interaction logic.&lt;/p&gt;

&lt;p&gt;Angular Aria currently supports these major patterns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tabs&lt;/li&gt;
&lt;li&gt;Accordion&lt;/li&gt;
&lt;li&gt;Combobox&lt;/li&gt;
&lt;li&gt;Listbox&lt;/li&gt;
&lt;li&gt;Select&lt;/li&gt;
&lt;li&gt;Multiselect&lt;/li&gt;
&lt;li&gt;Menu&lt;/li&gt;
&lt;li&gt;Menubar&lt;/li&gt;
&lt;li&gt;Toolbar&lt;/li&gt;
&lt;li&gt;Grid&lt;/li&gt;
&lt;li&gt;Tree&lt;/li&gt;
&lt;li&gt;Autocomplete&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In short: Angular Aria ensures components behave &lt;em&gt;correctly&lt;/em&gt; for all users, including those relying on assistive technologies.&lt;/p&gt;




&lt;h1&gt;
  
  
  What Is Angular Primitives?
&lt;/h1&gt;

&lt;p&gt;Angular Primitives (angularprimitives.com) is a &lt;strong&gt;community-driven library&lt;/strong&gt; that provides &lt;strong&gt;low-level composable utilities&lt;/strong&gt; — much like Radix UI, Headless UI, or React Aria Primitive hooks in the React ecosystem.&lt;/p&gt;

&lt;p&gt;Its goal is different from Angular Aria:&lt;/p&gt;

&lt;p&gt;Instead of giving you ARIA-compliant components, Angular Primitives gives you &lt;strong&gt;the building blocks&lt;/strong&gt; needed to create your own component logic such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dialog and modal behavior&lt;/li&gt;
&lt;li&gt;Popover and floating positioning&lt;/li&gt;
&lt;li&gt;Click-outside detection&lt;/li&gt;
&lt;li&gt;Toggle state&lt;/li&gt;
&lt;li&gt;Collapsed/disclosure logic&lt;/li&gt;
&lt;li&gt;Stores and reactive utilities&lt;/li&gt;
&lt;li&gt;Focus traps&lt;/li&gt;
&lt;li&gt;Motion and transition helpers&lt;/li&gt;
&lt;li&gt;Overlay logic&lt;/li&gt;
&lt;li&gt;Accessible patterns for interactions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Angular Primitives is about &lt;strong&gt;interaction mechanics&lt;/strong&gt;, not full ARIA patterns.&lt;/p&gt;

&lt;p&gt;It is perfect for building things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Custom dialogs&lt;/li&gt;
&lt;li&gt;Custom popovers&lt;/li&gt;
&lt;li&gt;Custom dropdown logic&lt;/li&gt;
&lt;li&gt;Custom tooltips&lt;/li&gt;
&lt;li&gt;Custom toggle controls&lt;/li&gt;
&lt;li&gt;Custom multi-step flows&lt;/li&gt;
&lt;li&gt;Custom interactive UI widgets&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All while remaining unstyled and flexible.&lt;/p&gt;




&lt;h1&gt;
  
  
  How Angular Aria and Angular Primitives Differ
&lt;/h1&gt;

&lt;p&gt;Here is the simplest way to think about the difference:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Angular Aria = Accessibility Behavior (Official)&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Angular Primitives = Interaction Logic (Community)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;More specifically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Angular Aria focuses on &lt;em&gt;accessibility and ARIA correctness&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Angular Primitives focuses on &lt;em&gt;composable UI behaviors and state&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Angular Aria gives entire UI patterns (tabs, menus, combobox…)&lt;/li&gt;
&lt;li&gt;Angular Primitives gives low-level utilities (popover, toggle, click-outside…)&lt;/li&gt;
&lt;li&gt;Angular Aria is about meeting accessibility standards&lt;/li&gt;
&lt;li&gt;Angular Primitives is about building custom, interactive experiences&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Another way to say it:&lt;/p&gt;

&lt;p&gt;Angular Aria is "what accessible UI patterns should do."&lt;br&gt;
Angular Primitives is "how UI components actually behave and interact."&lt;/p&gt;




&lt;h1&gt;
  
  
  Where They Overlap
&lt;/h1&gt;

&lt;p&gt;Both:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Are headless (unstyled)&lt;/li&gt;
&lt;li&gt;Focus on custom component building&lt;/li&gt;
&lt;li&gt;Encourage composability&lt;/li&gt;
&lt;li&gt;Improve developer ergonomics&lt;/li&gt;
&lt;li&gt;Fit perfectly into design-system workflows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because they have different goals, they rarely conflict.&lt;/p&gt;




&lt;h1&gt;
  
  
  How They Work Together (The Powerful Combination)
&lt;/h1&gt;

&lt;p&gt;Using Angular Aria and Angular Primitives together gives you maximum power.&lt;/p&gt;

&lt;p&gt;Example: You want to build a fully custom Select/Combobox component.&lt;/p&gt;

&lt;p&gt;Angular Aria provides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Listbox behavior&lt;/li&gt;
&lt;li&gt;Keyboard navigation&lt;/li&gt;
&lt;li&gt;Screen reader patterns&lt;/li&gt;
&lt;li&gt;ARIA roles and attributes&lt;/li&gt;
&lt;li&gt;Accessibility state&lt;/li&gt;
&lt;li&gt;Focus management&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Angular Primitives provides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Popover open/close logic&lt;/li&gt;
&lt;li&gt;Floating panel positioning&lt;/li&gt;
&lt;li&gt;Arrow key open/close behavior&lt;/li&gt;
&lt;li&gt;Click outside to dismiss&lt;/li&gt;
&lt;li&gt;Animate the dropdown&lt;/li&gt;
&lt;li&gt;Manage local state&lt;/li&gt;
&lt;li&gt;Trap focus when expanded&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Combine both, and you get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fully custom design&lt;/li&gt;
&lt;li&gt;Fully accessible&lt;/li&gt;
&lt;li&gt;Fully interactive&lt;/li&gt;
&lt;li&gt;Perfect ARIA compliance&lt;/li&gt;
&lt;li&gt;Minimal boilerplate&lt;/li&gt;
&lt;li&gt;No dependence on Angular Material or heavy UI kits&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the &lt;strong&gt;ideal combination for building your own design system&lt;/strong&gt;.&lt;/p&gt;




&lt;h1&gt;
  
  
  When To Use Angular Aria
&lt;/h1&gt;

&lt;p&gt;Use Angular Aria when you need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fully accessible UI components&lt;/li&gt;
&lt;li&gt;ARIA-compliant patterns (tabs, accordion, grid, tree, menu…)&lt;/li&gt;
&lt;li&gt;A custom design system with accessibility built in&lt;/li&gt;
&lt;li&gt;Complex components like Combobox or Listbox&lt;/li&gt;
&lt;li&gt;Consistent, official Angular tooling&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is best for enterprise apps, public-sector apps, or any project where accessibility cannot be optional.&lt;/p&gt;




&lt;h1&gt;
  
  
  When To Use Angular Primitives
&lt;/h1&gt;

&lt;p&gt;Use Angular Primitives when you need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Low-level interactive logic&lt;/li&gt;
&lt;li&gt;Dialog behavior&lt;/li&gt;
&lt;li&gt;Popover logic&lt;/li&gt;
&lt;li&gt;Floating UI positioning&lt;/li&gt;
&lt;li&gt;Toggle or disclosure mechanics&lt;/li&gt;
&lt;li&gt;Overlay management&lt;/li&gt;
&lt;li&gt;Stores and shared reactive state&lt;/li&gt;
&lt;li&gt;Click-outside detection&lt;/li&gt;
&lt;li&gt;Motion and transitions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is best for building deeply customized UI behaviors and complex components.&lt;/p&gt;




&lt;h1&gt;
  
  
  When You Should Use Both Together
&lt;/h1&gt;

&lt;p&gt;Use both when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You are building a design system&lt;/li&gt;
&lt;li&gt;You want strong accessibility and rich interactions&lt;/li&gt;
&lt;li&gt;You want complete styling freedom&lt;/li&gt;
&lt;li&gt;You prefer headless, composable component architecture&lt;/li&gt;
&lt;li&gt;You want to replace Angular Material with a fully custom UI suite&lt;/li&gt;
&lt;li&gt;You need both ARIA correctness and complex UI behaviors&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This combination is becoming a modern best practice in the Angular ecosystem.&lt;/p&gt;




&lt;h1&gt;
  
  
  Summary
&lt;/h1&gt;

&lt;p&gt;Angular Aria and Angular Primitives are not competitors — they are complementary tools that operate on different layers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Angular Aria gives you &lt;strong&gt;officially supported ARIA-compliant UI patterns&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Angular Primitives gives you &lt;strong&gt;interaction primitives and utilities&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Together, they form a powerful foundation for building fully custom, fully accessible, and highly interactive UI components — an essential approach for modern Angular applications and design systems.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>angular</category>
      <category>frontend</category>
      <category>a11y</category>
    </item>
    <item>
      <title>Angular Aria in Angular 21: The Future of Accessible, Headless UI Components</title>
      <dc:creator>hassantayyab</dc:creator>
      <pubDate>Wed, 26 Nov 2025 12:00:36 +0000</pubDate>
      <link>https://dev.to/hassantayyab/angular-aria-in-angular-21-the-future-of-accessible-headless-ui-components-26di</link>
      <guid>https://dev.to/hassantayyab/angular-aria-in-angular-21-the-future-of-accessible-headless-ui-components-26di</guid>
      <description>&lt;p&gt;Accessibility has become one of the most important pillars of modern web development. With Angular 21, the framework takes a huge leap forward with &lt;strong&gt;Angular Aria&lt;/strong&gt;, a brand-new package that delivers &lt;em&gt;headless, accessibility-ready UI patterns&lt;/em&gt; out of the box — without enforcing any styling or visual design.&lt;/p&gt;

&lt;p&gt;Angular Aria brings powerful, production-ready accessibility to your custom UI components while giving you full control over markup and CSS. If you’re building design systems, enterprise dashboards, or any rich interactive UI, this new feature dramatically reduces the complexity of building accessible components.&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 What Is Angular Aria?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Angular Aria&lt;/strong&gt; is a new library introduced in Angular 21 to standardize accessibility behaviors for commonly used interactive UI patterns. It handles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ARIA roles &amp;amp; attributes&lt;/li&gt;
&lt;li&gt;Keyboard navigation&lt;/li&gt;
&lt;li&gt;Focus management&lt;/li&gt;
&lt;li&gt;Screen-reader semantics&lt;/li&gt;
&lt;li&gt;Interaction state management&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All while remaining &lt;strong&gt;unstyled and fully customizable&lt;/strong&gt;, allowing you to craft your own visual identity.&lt;/p&gt;

&lt;p&gt;Instead of manually implementing complex accessibility rules, you use Angular Aria’s directives — and the accessibility logic is done for you.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧩 Supported UI Patterns in Angular Aria
&lt;/h2&gt;

&lt;p&gt;Here are the major patterns available in the first release:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;🔹 Inputs &amp;amp; Selection&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Autocomplete&lt;/li&gt;
&lt;li&gt;Listbox&lt;/li&gt;
&lt;li&gt;Select&lt;/li&gt;
&lt;li&gt;Multiselect&lt;/li&gt;
&lt;li&gt;Combobox&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;🔹 Navigation &amp;amp; Menus&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Menu&lt;/li&gt;
&lt;li&gt;Menubar&lt;/li&gt;
&lt;li&gt;Toolbar&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;🔹 Structure &amp;amp; Content Organization&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Accordion&lt;/li&gt;
&lt;li&gt;Tabs&lt;/li&gt;
&lt;li&gt;Tree&lt;/li&gt;
&lt;li&gt;Grid&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These patterns cover a large portion of real-world accessibility needs — especially in design systems and enterprise-grade apps.&lt;/p&gt;




&lt;h2&gt;
  
  
  🎯 Why Angular Aria Matters
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1. Accessibility by Default&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Accessibility is complex — especially with dynamic components like menus or comboboxes. Angular Aria builds accessibility &lt;em&gt;into the logic&lt;/em&gt;, so your UI is accessible without manual ARIA implementation.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;2. Headless Architecture&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;You control:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTML&lt;/li&gt;
&lt;li&gt;CSS&lt;/li&gt;
&lt;li&gt;Layout&lt;/li&gt;
&lt;li&gt;Branding&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Angular Aria only provides the behaviors — perfect for custom design systems.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;3. Enterprise-Friendly&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Teams maintaining multiple apps can rely on Angular Aria to ensure accessibility consistency across all projects.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;4. Better Developer Experience&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;You no longer need to memorize ARIA rules or behavior patterns. The library handles them so you can focus on productivity.&lt;/p&gt;




&lt;h2&gt;
  
  
  🎨 Example: Simple Accessible Toolbar
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;Toolbar&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;ToolbarWidget&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;ToolbarWidgetGroup&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="s1"&gt;@angular/aria/toolbar&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;ngToolbar&lt;/span&gt; &lt;span class="na"&gt;aria-label=&lt;/span&gt;&lt;span class="s"&gt;"Text Controls"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"group"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;ngToolbarWidget&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"undo"&lt;/span&gt; &lt;span class="na"&gt;aria-label=&lt;/span&gt;&lt;span class="s"&gt;"Undo"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Undo&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;ngToolbarWidget&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"redo"&lt;/span&gt; &lt;span class="na"&gt;aria-label=&lt;/span&gt;&lt;span class="s"&gt;"Redo"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Redo&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"group"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;ngToolbarWidget&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"bold"&lt;/span&gt; &lt;span class="na"&gt;aria-label=&lt;/span&gt;&lt;span class="s"&gt;"Bold"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Bold&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;ngToolbarWidget&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"italic"&lt;/span&gt; &lt;span class="na"&gt;aria-label=&lt;/span&gt;&lt;span class="s"&gt;"Italic"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Italic&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Accessible: ✔️&lt;br&gt;
Keyboard-friendly: ✔️&lt;br&gt;
Screen-reader ready: ✔️&lt;br&gt;
No extra work required: ✔️&lt;/p&gt;




&lt;h2&gt;
  
  
  🛠️ Getting Started With Angular Aria
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Install the package&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&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; @angular/aria
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Import the pattern module you need&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;Tabs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Tab&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;TabPanel&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="s1"&gt;@angular/aria/tabs&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;ol&gt;
&lt;li&gt;
&lt;strong&gt;Use the directives in your templates&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;ngTabs&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;ngTab=&lt;/span&gt;&lt;span class="s"&gt;"tab1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Overview&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;ngTab=&lt;/span&gt;&lt;span class="s"&gt;"tab2"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Details&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;section&lt;/span&gt; &lt;span class="na"&gt;ngTabPanel=&lt;/span&gt;&lt;span class="s"&gt;"tab1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Overview content…&lt;span class="nt"&gt;&amp;lt;/section&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;section&lt;/span&gt; &lt;span class="na"&gt;ngTabPanel=&lt;/span&gt;&lt;span class="s"&gt;"tab2"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Detailed content…&lt;span class="nt"&gt;&amp;lt;/section&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Add your own styling&lt;/strong&gt;
Angular Aria provides no CSS — giving you full creative freedom.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  📘 &lt;strong&gt;Angular Aria Cheat Sheet (Quick Reference)&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Installation&lt;/strong&gt;
&lt;/h3&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; @angular/aria
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  &lt;strong&gt;Common Imports&lt;/strong&gt;
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pattern&lt;/th&gt;
&lt;th&gt;Import Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Tabs&lt;/td&gt;
&lt;td&gt;&lt;code&gt;import { Tabs, Tab, TabPanel } from '@angular/aria/tabs';&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Accordion&lt;/td&gt;
&lt;td&gt;&lt;code&gt;import { Accordion, AccordionItem } from '@angular/aria/accordion';&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Menu&lt;/td&gt;
&lt;td&gt;&lt;code&gt;import { Menu, Menuitem } from '@angular/aria/menu';&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Toolbar&lt;/td&gt;
&lt;td&gt;&lt;code&gt;import { Toolbar, ToolbarWidget } from '@angular/aria/toolbar';&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Listbox&lt;/td&gt;
&lt;td&gt;&lt;code&gt;import { Listbox, ListboxOption } from '@angular/aria/listbox';&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Combobox&lt;/td&gt;
&lt;td&gt;&lt;code&gt;import { Combobox, ComboboxOption } from '@angular/aria/combobox';&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Directive Patterns&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Tabs&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;ngTabs&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;ngTab=&lt;/span&gt;&lt;span class="s"&gt;"id1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Tab 1&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;section&lt;/span&gt; &lt;span class="na"&gt;ngTabPanel=&lt;/span&gt;&lt;span class="s"&gt;"id1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Content 1&lt;span class="nt"&gt;&amp;lt;/section&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Accordion&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;ngAccordion&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;ngAccordionItem&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;ngAccordionItemToggle&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Title&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;section&lt;/span&gt; &lt;span class="na"&gt;ngAccordionItemPanel&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Content&lt;span class="nt"&gt;&amp;lt;/section&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Menu&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ul&lt;/span&gt; &lt;span class="na"&gt;ngMenu&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&lt;/span&gt; &lt;span class="na"&gt;ngMenuItem&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Profile&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&lt;/span&gt; &lt;span class="na"&gt;ngMenuItem&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Settings&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Listbox&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ul&lt;/span&gt; &lt;span class="na"&gt;ngListbox&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&lt;/span&gt; &lt;span class="na"&gt;ngListboxOption&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Option A&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&lt;/span&gt; &lt;span class="na"&gt;ngListboxOption&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"2"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Option B&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Combobox&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;ngCombobox&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;ul&lt;/span&gt; &lt;span class="na"&gt;ngComboboxOptions&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&lt;/span&gt; &lt;span class="na"&gt;ngComboboxOption&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"alpha"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Alpha&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  &lt;strong&gt;Keyboard Support (Handled Automatically)&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Example behaviors Angular Aria manages:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Arrow keys for navigation&lt;/li&gt;
&lt;li&gt;Enter/Space for selection&lt;/li&gt;
&lt;li&gt;Escape for closing menus&lt;/li&gt;
&lt;li&gt;Tab/Shift+Tab focus trapping&lt;/li&gt;
&lt;li&gt;Focus restoration when components close&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You don’t implement any of this manually — Angular Aria does it.&lt;/p&gt;




&lt;h2&gt;
  
  
  📚 &lt;strong&gt;Further Reading &amp;amp; Resources&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;For detailed documentation, examples, and the full API reference, visit:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;Angular Aria Official Documentation&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://angular.dev/guide/aria/overview" rel="noopener noreferrer"&gt;https://angular.dev/guide/aria/overview&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>angular</category>
      <category>frontend</category>
      <category>a11y</category>
    </item>
    <item>
      <title>Building fast in Angular with Zard UI Tailwind CSS Signals and NgRx</title>
      <dc:creator>hassantayyab</dc:creator>
      <pubDate>Tue, 25 Nov 2025 11:26:59 +0000</pubDate>
      <link>https://dev.to/hassantayyab/building-fast-in-angular-with-zard-ui-tailwind-css-signals-and-ngrx-57ld</link>
      <guid>https://dev.to/hassantayyab/building-fast-in-angular-with-zard-ui-tailwind-css-signals-and-ngrx-57ld</guid>
      <description>&lt;p&gt;If you are building products in a startup environment you do not have time to reinvent buttons and argue about folder structures for a week.&lt;/p&gt;

&lt;p&gt;You need to ship.&lt;/p&gt;

&lt;p&gt;Modern Angular actually makes that pretty fun&lt;br&gt;
Especially when you combine four things&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Zard UI&lt;/li&gt;
&lt;li&gt;Tailwind CSS&lt;/li&gt;
&lt;li&gt;Angular’s new signals and control flow&lt;/li&gt;
&lt;li&gt;NgRx when your state gets serious&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Add a couple of small helper libraries on top and you get a stack that lets you move very fast without your codebase turning into chaos.&lt;/p&gt;

&lt;p&gt;Let’s break it down.&lt;/p&gt;


&lt;h2&gt;
  
  
  1. Why this stack is so fast
&lt;/h2&gt;

&lt;p&gt;Most frontend time is lost in three places&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Designing and styling basic UI from scratch&lt;/li&gt;
&lt;li&gt;Rewriting state management every project&lt;/li&gt;
&lt;li&gt;Fighting with inconsistent patterns between team members&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Zard UI and Tailwind handle the first part&lt;br&gt;
Signals and NgRx handle the second&lt;br&gt;
Angular itself handles the third with its opinionated structure&lt;/p&gt;

&lt;p&gt;You get speed without giving up structure.&lt;/p&gt;


&lt;h2&gt;
  
  
  2. Zard UI – plug in real components instead of drawing them
&lt;/h2&gt;

&lt;p&gt;Zard UI gives you a set of ready made Angular components inspired by modern headless and design system libraries.&lt;/p&gt;

&lt;p&gt;Things like&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Buttons&lt;/li&gt;
&lt;li&gt;Dialogs&lt;/li&gt;
&lt;li&gt;Dropdown menus&lt;/li&gt;
&lt;li&gt;Menus and navigation&lt;/li&gt;
&lt;li&gt;Inputs and forms&lt;/li&gt;
&lt;li&gt;Toasts and alerts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of designing all of these from zero you drop them in wire them to your data and you are done.&lt;/p&gt;
&lt;h3&gt;
  
  
  Why it helps you move faster
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You stop re designing basic components every project&lt;/li&gt;
&lt;li&gt;You get accessibility and interaction patterns handled for you&lt;/li&gt;
&lt;li&gt;You keep a consistent look and feel across the app&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For an MVP you can have a clean UI in a day instead of a week&lt;br&gt;
And because components are composable you can still customize them when you actually need to.&lt;/p&gt;


&lt;h2&gt;
  
  
  3. Tailwind CSS – styling without bike shedding
&lt;/h2&gt;

&lt;p&gt;Tailwind fits this really well.&lt;/p&gt;

&lt;p&gt;You write your styles as utility classes in the template&lt;br&gt;
No long naming debates&lt;br&gt;
No giant CSS files you are scared to touch months later.&lt;/p&gt;

&lt;p&gt;Example&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt;
  &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"px-4 py-2 rounded-xl text-sm font-medium bg-blue-600 hover:bg-blue-700 text-white"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  Save
&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is readable and you see the styling right in the markup.&lt;br&gt;
Design tweaks become quick edits not refactors.&lt;/p&gt;
&lt;h3&gt;
  
  
  Tailwind plus Zard UI
&lt;/h3&gt;

&lt;p&gt;Most components expose class or style hooks so your workflow becomes&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Drop a Zard UI component&lt;/li&gt;
&lt;li&gt;Add or tweak Tailwind classes&lt;/li&gt;
&lt;li&gt;Ship&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You stay in flow and you rarely have to open a separate CSS file.&lt;/p&gt;


&lt;h2&gt;
  
  
  4. State management with Signals first NgRx when it matters
&lt;/h2&gt;

&lt;p&gt;This is where many Angular apps either stay clean or become pain.&lt;/p&gt;
&lt;h3&gt;
  
  
  Start with Angular signals for local and feature level state
&lt;/h3&gt;

&lt;p&gt;For a lot of early stage or smaller features you do not need a full global store.&lt;br&gt;
Angular’s signals give you a simple pull based mental model.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;signal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;computed&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="s1"&gt;@angular/core&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="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UsersComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&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;loading&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;signal&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;totalUsers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;computed&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;users&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="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;loadUsers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getUsers&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Template&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;@if (loading()) {
  &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Loading users...&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
} @else {
  &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Total users {{ totalUsers() }}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;

  @for (user of users(); track user.id) {
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"p-3 rounded-lg border mb-2"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      {{ user.name }}
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Signals are perfect when&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The state is local to a component or small feature&lt;/li&gt;
&lt;li&gt;Only a few components need the same data&lt;/li&gt;
&lt;li&gt;You are still exploring the product and requirements move fast&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You write less boilerplate and you can refactor easily later.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bring in NgRx when the app and data sharing grow
&lt;/h3&gt;

&lt;p&gt;At some point you hit problems that signals alone should not solve&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Many components across the app rely on the same data&lt;/li&gt;
&lt;li&gt;You need predictable behaviour on complex flows&lt;/li&gt;
&lt;li&gt;You want time travel debugging or strict immutability&lt;/li&gt;
&lt;li&gt;You start duplicating fetch and update logic in multiple places&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is where NgRx earns its place.&lt;/p&gt;

&lt;p&gt;You move shared and complex state out of random services and into feature stores.&lt;br&gt;
Signals can still live at the edge of the UI to map store data to components&lt;br&gt;
But NgRx holds the source of truth.&lt;/p&gt;

&lt;p&gt;Typical pattern&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use signals and simple services for local UI state
modal open flags form steps local filters&lt;/li&gt;
&lt;li&gt;Use NgRx for domain level state shared across screens
auth user profile entities lists cart etc&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This gives you&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A clear separation between UI state and application state&lt;/li&gt;
&lt;li&gt;A single source of truth for important data&lt;/li&gt;
&lt;li&gt;Scalable patterns when the team grows and multiple people touch the same features&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The key is timing&lt;br&gt;
Do not force NgRx on day one for a tiny MVP&lt;br&gt;
Introduce it when you feel real pain from shared or duplicated state.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. A few extra helpers that keep things fast
&lt;/h2&gt;

&lt;p&gt;Some small tools that work nicely with this setup&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Angular CDK&lt;/strong&gt;&lt;br&gt;
Overlays drag and drop portals accessibility tools.&lt;br&gt;
Often enough for custom interactions without huge dependencies.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Zod or Valibot with Angular forms&lt;/strong&gt;&lt;br&gt;
You define the schema once&lt;br&gt;
Use it for validation on the client and server&lt;br&gt;
This keeps your forms honest and type safe.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A query style data fetching layer if needed&lt;/strong&gt;&lt;br&gt;
You can pair NgRx with entity adapters or use a query library for server state.&lt;br&gt;
Either way the goal is the same&lt;br&gt;
caching loading error handling in one place instead of every component doing its own thing.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You do not need all of these from day one&lt;br&gt;
You add them when you hit a real problem.&lt;/p&gt;




&lt;h2&gt;
  
  
  6. A simple “fast stack” blueprint
&lt;/h2&gt;

&lt;p&gt;If I was starting a new Angular product today and I cared about speed and long term health this is what I would do&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use Angular with standalone components new control flow and signals&lt;/li&gt;
&lt;li&gt;Add Tailwind CSS for styling&lt;/li&gt;
&lt;li&gt;Add Zard UI for core UI primitives buttons dialogs forms toasts&lt;/li&gt;
&lt;li&gt;Use signals plus lightweight services for local and feature state&lt;/li&gt;
&lt;li&gt;When multiple parts of the app depend on the same data introduce NgRx for that domain and keep using signals at the component level&lt;/li&gt;
&lt;li&gt;Only add extra libs when they remove real pain not just because they look cool&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Rule&lt;br&gt;
If it does not help me ship in the next week it goes to the backlog.&lt;/p&gt;




&lt;h2&gt;
  
  
  7. Mindset still beats stack
&lt;/h2&gt;

&lt;p&gt;All of this works only if the mindset matches&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reuse existing components before building new ones&lt;/li&gt;
&lt;li&gt;Avoid premature “enterprise” architecture for a tiny product&lt;/li&gt;
&lt;li&gt;Keep your first versions simple but shippable&lt;/li&gt;
&lt;li&gt;Refactor when it actually hurts not just because you are bored&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Angular gives enough structure that you can move fast without creating a junkyard.&lt;br&gt;
Signals Zard UI Tailwind and NgRx just make the path smoother.&lt;/p&gt;




&lt;h2&gt;
  
  
  Closing thoughts
&lt;/h2&gt;

&lt;p&gt;Angular today is not the heavy slow framework people remember from years ago.&lt;br&gt;
With Zard UI Tailwind CSS signals and NgRx used at the right time you can build modern apps that ship fast now and stay maintainable later.&lt;/p&gt;

&lt;p&gt;I will hopefully share my real world experience with this stack in a post very soon and drop it here for everyone 😊&lt;/p&gt;

&lt;p&gt;And I am curious&lt;br&gt;
How are you mixing signals and NgRx in your Angular apps right now?&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>frontend</category>
      <category>angular</category>
    </item>
  </channel>
</rss>
