DEV Community

Pavan S Poojary
Pavan S Poojary

Posted on

Stop hardcoding <Banner /> modals in your Next.js codebase

Every SaaS team starts the same way: a simple boolean column in PostgreSQL (has_seen_v2_modal), a useEffect hook, and a conditional modal component.

Fast forward 6 months, and your frontend bundle is 80KB heavier with 14 dead announcement modals, 3 hydration race conditions, and marketing asking why the banner didn't trigger for trial users.

Here is why hardcoding in-app experiences is an anti-pattern—and how to architect a deterministic, decoupled announcement engine in Next.js.


The 3 Inevitable Failures of Hardcoded In-App UI

When engineering teams build announcement modals directly into application code, three major issues arise:

  1. Bundle Bloat: Every new changelog modal, tooltip, or onboarding banner adds unused HTML/CSS to the initial page load.
  2. Hydration Mismatch: Checking localStorage during SSR causes classic React hydration warnings or jarring layout flashes.
  3. Deployment Friction: Fixing a single typo in an announcement requires a full git commit, CI/CD pipeline run, and production deployment.

The Clean Solution: Deterministic Experience Slots

Instead of embedding static modals inside your page layouts, register a lightweight, polymorphic <ExperienceSlot /> container. This container evaluates targeting rules (such as page.path, user.plan, and session.count) at runtime.

// app/dashboard/layout.tsx
import { ExperienceSlot } from '@neotic/react';

export default function DashboardLayout({ children }: { children: React.ReactNode }) {
  return (
    <div className="min-h-screen bg-slate-950 text-white">
      {/* Dynamic, rule-evaluated announcement slot */}
      <ExperienceSlot 
        slotId="dashboard-top-banner"
        context={{
          plan: user.plan,
          daysActive: user.daysActive,
          path: '/dashboard'
        }}
        fallback={null}
      />

      <main className="p-8">
        {children}
      </main>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Because the client SDK is <4KB gzipped, you get sub-millisecond local rule evaluation without dragging down your Core Web Vitals (LCP/INP).

Automating with AI Agents via Model Context Protocol (MCP)

The real breakthrough happens when you hook this up to your AI coding agents (Claude Code, Cursor, Windsurf). Instead of asking an AI agent to rewrite React components every time you launch a feature, you can connect an open Model Context Protocol (MCP) server.

We set up Neotic with an open remote MCP endpoint (https://www.neotic.app/api/mcp). Now, when you ship an update, you simply prompt your agent:

"Announce the new CSV Export feature to all Pro tier users on the /reports route for the next 14 days."

The agent interacts with the MCP server to configure the deterministic JSON targeting rule, and it goes live instantly with zero frontend redeployments.


💬 Let's Discuss

How does your team currently manage in-app announcements and feature onboarding? Do you hardcode modals into React, use an external script, or automate via MCP? Drop your thoughts below!

(If you're building with Next.js or AI coding agents, check out Neotic and our remote MCP endpoint at https://www.neotic.app/api/mcp!)

Top comments (0)