DEV Community

Cover image for Day 59 of #100DayOfCode — Styling the Task Management App
M Saad Ahmad
M Saad Ahmad

Posted on

Day 59 of #100DayOfCode — Styling the Task Management App

Yesterday on Day 58, I built a Task Manager app with Next.js, MongoDB, and Server Actions. The app worked, but it looked rough. Today was all about making it actually nice to use.

What I Used

  • Tailwind CSS — for layout and spacing utilities
  • Shadcn UI — for pre-built, accessible components I can own and customize

Setting Up Shadcn

npx shadcn@latest init
npx shadcn@latest add button card badge input textarea select label
Enter fullscreen mode Exit fullscreen mode

This drops the component source directly into your project under /components/ui. No black-box library — you own the code.

What I Styled

Layout — A clean navbar with a centered max-w-4xl main container across all pages.

Task List — A responsive 2-column grid on larger screens, with a friendly empty state when no tasks exist yet.

Task Cards — Each task is wrapped in a Card with the title, a colored status badge, description, timestamps, and Edit/Delete actions.

Task Form — Proper Label + Input/Textarea/Select combinations with placeholders, and a dynamic submit button that says "Create Task" or "Update Task" depending on the context.

A Gotcha with Shadcn Badge

Shadcn's Badge only ships with 4 variants: default, secondary, destructive, outline. There's no built-in success or warning.

Instead of extending the component, I used a simple helper with Tailwind classes directly:

const statusStyles = (status) => {
  if (status === "completed") return "bg-green-100 text-green-700 hover:bg-green-100";
  if (status === "in-progress") return "bg-yellow-100 text-yellow-700 hover:bg-yellow-100";
  return "bg-gray-100 text-gray-600 hover:bg-gray-100";
};

<Badge className={statusStyles(task.status)}>{task.status}</Badge>
Enter fullscreen mode Exit fullscreen mode

Clean enough, and no need to touch the component internals.

Using Button with asChild

Shadcn's Button has an asChild prop that lets you pass a Link inside it and get all the button styles applied to the anchor — no wrapper divs needed:

<Button asChild variant="outline" size="sm">
  <Link href={`/tasks/${task._id}`}>Edit</Link>
</Button>
Enter fullscreen mode Exit fullscreen mode

This is one of those small things that makes Shadcn feel really well thought out.

Key Takeaway

Shadcn isn't a traditional component library. You install only what you need, and the code lives in your project. That means full control — no fighting with overrides or !important hacks.

Tomorrow, for Day 60, I'll be deploying the app on Vercel.

Top comments (0)