{"id":1376,"date":"2026-07-30T05:44:23","date_gmt":"2026-07-30T05:44:23","guid":{"rendered":"https:\/\/www.projectimmerse.com\/blog\/?p=1376"},"modified":"2026-07-30T19:56:27","modified_gmt":"2026-07-30T19:56:27","slug":"building-my-first-next-js-project-components-props-arrays-and-dynamic-progress-bars","status":"publish","type":"post","link":"https:\/\/www.projectimmerse.com\/blog\/building-my-first-next-js-project-components-props-arrays-and-dynamic-progress-bars\/","title":{"rendered":"Building My First Next.js Project: Components, Props, Arrays, and Dynamic Progress Bars"},"content":{"rendered":"\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.projectimmerse.com\/blog\/building-my-first-next-js-project-components-props-arrays-and-dynamic-progress-bars\/\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"1024\" src=\"https:\/\/www.projectimmerse.com\/blog\/wp-content\/uploads\/2026\/07\/building-first-nextjs-app-components-props-arrays-1024x1024.png\" alt=\"Building a Next.js Project Progress Tracker while learning React components, props, arrays, TypeScript, and dynamic UI\" class=\"wp-image-1379\" srcset=\"https:\/\/www.projectimmerse.com\/blog\/wp-content\/uploads\/2026\/07\/building-first-nextjs-app-components-props-arrays-1024x1024.png 1024w, https:\/\/www.projectimmerse.com\/blog\/wp-content\/uploads\/2026\/07\/building-first-nextjs-app-components-props-arrays-300x300.png 300w, https:\/\/www.projectimmerse.com\/blog\/wp-content\/uploads\/2026\/07\/building-first-nextjs-app-components-props-arrays-150x150.png 150w, https:\/\/www.projectimmerse.com\/blog\/wp-content\/uploads\/2026\/07\/building-first-nextjs-app-components-props-arrays-768x768.png 768w, https:\/\/www.projectimmerse.com\/blog\/wp-content\/uploads\/2026\/07\/building-first-nextjs-app-components-props-arrays-100x100.png 100w, https:\/\/www.projectimmerse.com\/blog\/wp-content\/uploads\/2026\/07\/building-first-nextjs-app-components-props-arrays.png 1254w\" sizes=\"auto, (max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/a><figcaption class=\"wp-element-caption\">Building a Project Progress Tracker while learning the fundamentals of Next.js, React, TypeScript, and dynamic UI development.<\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Learning a new framework is always a little strange at first.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">You install a bunch of packages, the terminal spits out enough text to make you question your career choices, and suddenly you&#8217;re staring at files with names like <code>page.tsx<\/code> wondering what exactly you signed up for.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That\u2019s where my latest project begins.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I\u2019m building a simple <strong>Project Progress Tracker with Next.js<\/strong>. The idea is straightforward: create an application that tracks the other applications I build, including how far along each project is.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Yes, I\u2019m building a project to track my projects. We\u2019re officially through the looking glass.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">More importantly, the app gives me a practical way to learn Next.js and React concepts instead of working through isolated examples that never turn into anything useful.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">So far, I\u2019ve covered components, props, TypeScript types, arrays, objects, <code>.map()<\/code>, JSX, Tailwind CSS, and dynamic progress bars.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Here\u2019s what I\u2019ve learned along the way.<\/p>\n\n\n\n<!--more-->\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Starting With Next.js<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The project was created using <code>create-next-app<\/code>, which gives you the basic structure needed for a modern Next.js application.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">One of the first important files is:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\napp\/page.tsx\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">With the Next.js App Router, this file represents the application&#8217;s home page.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Visit:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nlocalhost:3000\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">and Next.js renders the component exported from <code>page.tsx<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">My first version was intentionally simple:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\nexport default function Home() {\n  return (\n    &lt;main className=&quot;p-8&quot;&gt;\n      &lt;h1 className=&quot;text-4xl font-bold&quot;&gt;\n        Project Progress Tracker\n      &lt;\/h1&gt;\n\n      &lt;p className=&quot;mt-4 text-gray-600&quot;&gt;\n        Track every app you build from idea to deployment.\n      &lt;\/p&gt;\n    &lt;\/main&gt;\n  );\n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">There isn&#8217;t much happening yet, but even this small example introduces several important concepts.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The <code>Home<\/code> function is a React component.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The markup inside <code>return<\/code> is JSX.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">And classes such as:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\np-8\ntext-4xl\nfont-bold\nmt-4\ntext-gray-600\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">come from Tailwind CSS.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">At this stage, everything lived inside one component.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That works when an application contains approximately two sentences.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">It becomes considerably less charming when the file reaches 900 lines.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That brings us to components.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Understanding React Components<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">One of the core ideas behind React is breaking an interface into smaller pieces called <strong>components<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Instead of putting the entire application inside <code>page.tsx<\/code>, I created:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\ncomponents\/Header.tsx\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">The component looks like this:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\nexport default function Header() {\n  return (\n    &lt;header className=&quot;mb-8&quot;&gt;\n      &lt;h1 className=&quot;text-4xl font-bold&quot;&gt;\n        Project Progress Tracker\n      &lt;\/h1&gt;\n\n      &lt;p className=&quot;mt-4 text-gray-600&quot;&gt;\n        Track every app you build from idea to deployment.\n      &lt;\/p&gt;\n    &lt;\/header&gt;\n  );\n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">A React component is essentially a JavaScript function that returns JSX.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">But creating the file doesn&#8217;t automatically make it appear anywhere.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">It needs to be imported and rendered.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Inside <code>page.tsx<\/code>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nimport Header from &quot;@\/components\/Header&quot;;\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Then:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n&amp;lt;Header \/&gt;\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">The complete page becomes:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\nimport Header from &quot;@\/components\/Header&quot;;\n\nexport default function Home() {\n  return (\n    &lt;main className=&quot;p-8&quot;&gt;\n      &lt;Header \/&gt;\n    &lt;\/main&gt;\n  );\n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">The browser looks almost identical to before.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The underlying architecture, however, is better.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Instead of:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\npage.tsx\n\u251c\u2500\u2500 h1\n\u2514\u2500\u2500 p\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">I now have:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\npage.tsx\n\u2514\u2500\u2500 Header\n    \u251c\u2500\u2500 h1\n    \u2514\u2500\u2500 p\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">That distinction becomes increasingly important as an application grows.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Components Don&#8217;t Run Just Because They Exist<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">This was an important concept to clarify.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Creating:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nHeader.tsx\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">doesn&#8217;t mean Next.js automatically discovers it and displays it.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The component has to be used somewhere.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The basic flow is:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\nHeader.tsx\n     \u2193\nexport Header\n     \u2193\npage.tsx\n     \u2193\nimport Header\n     \u2193\n&lt;Header \/&gt;\n     \u2193\nReact renders the component\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">That helped make React components feel considerably less mysterious.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A component is essentially a function.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\n&lt;Header \/&gt;\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">causes React to render what the <code>Header<\/code> component returns.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Once that clicked, building additional components made much more sense.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Creating a Project Card Component<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The next component was the heart of the application:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\ncomponents\/ProjectCard.tsx\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Initially, the project card was completely hardcoded:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\nexport default function ProjectCard() {\n  return (\n    &lt;div className=&quot;mt-8 rounded-lg border p-6&quot;&gt;\n      &lt;h2 className=&quot;text-2xl font-semibold&quot;&gt;\n        Portfolio Website\n      &lt;\/h2&gt;\n\n      &lt;p className=&quot;mt-2 text-gray-600&quot;&gt;\n        Progress: 75%\n      &lt;\/p&gt;\n\n      &lt;p className=&quot;text-green-600&quot;&gt;\n        In Progress\n      &lt;\/p&gt;\n    &lt;\/div&gt;\n  );\n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">This worked.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Unfortunately, every project card would now be a 75%-complete portfolio website.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Unless I somehow decided to build twelve identical portfolio websites, this wasn&#8217;t going to scale.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That&#8217;s where props came in.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Understanding React Props<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Props allow data to be passed into a component.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Instead of permanently storing:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nPortfolio Website\n75%\nIn Progress\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">inside the component, I can provide those values whenever I create a <code>ProjectCard<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For example:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\n&lt;ProjectCard\n  title=&quot;Portfolio Website&quot;\n  progress={75}\n  status=&quot;In Progress&quot;\n\/&gt;\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">And another:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\n&lt;ProjectCard\n  title=&quot;Tracker App&quot;\n  progress={100}\n  status=&quot;Completed&quot;\n\/&gt;\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Same component.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Different data.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This is one of the concepts that makes React reusable.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Adding TypeScript to the Props<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Because the project uses TypeScript, the component also defines what type of data it&#8217;s expecting:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\ntype ProjectCardProps = {\n  title: string;\n  progress: number;\n  status: string;\n};\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">This says:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>title<\/code> must be a string<\/li>\n\n\n\n<li><code>progress<\/code> must be a number<\/li>\n\n\n\n<li><code>status<\/code> must be a string<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">The component can then receive those props:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\nexport default function ProjectCard({\n  title,\n  progress,\n  status,\n}: ProjectCardProps) {\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">And display them:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\n&lt;h2&gt;{title}&lt;\/h2&gt;\n\n&lt;p&gt;\n  Progress: {progress}%\n&lt;\/p&gt;\n\n&lt;p&gt;\n  {status}\n&lt;\/p&gt;\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">The full component at this stage looked like:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\ntype ProjectCardProps = {\n  title: string;\n  progress: number;\n  status: string;\n};\n\nexport default function ProjectCard({\n  title,\n  progress,\n  status,\n}: ProjectCardProps) {\n  return (\n    &lt;div className=&quot;mt-8 rounded-lg border p-6 shadow&quot;&gt;\n      &lt;h2 className=&quot;text-2xl font-semibold&quot;&gt;\n        {title}\n      &lt;\/h2&gt;\n\n      &lt;p className=&quot;mt-2 text-gray-600&quot;&gt;\n        Progress: {progress}%\n      &lt;\/p&gt;\n\n      &lt;p className=&quot;text-green-600&quot;&gt;\n        {status}\n      &lt;\/p&gt;\n    &lt;\/div&gt;\n  );\n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Now the component doesn&#8217;t care what project it&#8217;s displaying.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">It simply receives data and renders it.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Props Are Basically Function Arguments<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">One comparison helped make props easier to understand.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Consider a normal JavaScript function:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\nfunction greet(name) {\n  return `Hello ${name}`;\n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Calling:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\ngreet(&quot;Mark&quot;);\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">produces a different result than:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\ngreet(&quot;Sarah&quot;);\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">The function stays the same.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The input changes.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">React props follow the same basic idea.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Instead of:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\ngreet(&quot;Mark&quot;);\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">we might have:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\n&lt;ProjectCard title=&quot;Portfolio Website&quot; \/&gt;\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">The component is reusable because the data isn&#8217;t permanently baked into it.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Moving Project Data Into an Array<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The next problem became obvious pretty quickly.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I could manually write:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\n&lt;ProjectCard\n  title=&quot;Portfolio Website&quot;\n  progress={75}\n  status=&quot;In Progress&quot;\n\/&gt;\n\n&lt;ProjectCard\n  title=&quot;Tracker App&quot;\n  progress={100}\n  status=&quot;Completed&quot;\n\/&gt;\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">But imagine doing that for 30 projects.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Or 100.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">At some point, copy and paste stops being a workflow and starts becoming a cry for help.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Instead, I moved the project information into an array:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\nconst projects = &#x5B;\n  {\n    title: &quot;Portfolio Website&quot;,\n    progress: 75,\n    status: &quot;In Progress&quot;,\n  },\n  {\n    title: &quot;Tracker App&quot;,\n    progress: 100,\n    status: &quot;Completed&quot;,\n  },\n];\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">This introduced two fundamental JavaScript structures.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Arrays<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The square brackets represent an array:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nconst projects = &#x5B;];\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">An array is essentially a list of values.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Objects<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Each project is represented by an object:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\n{\n  title: &quot;Portfolio Website&quot;,\n  progress: 75,\n  status: &quot;In Progress&quot;,\n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">That object groups related information together.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Instead of having separate variables for every title, percentage, and status, everything belonging to one project lives together.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Rendering Projects With <code>.map()<\/code><\/h2>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"1024\" src=\"https:\/\/www.projectimmerse.com\/blog\/wp-content\/uploads\/2026\/07\/nextjs-components-props-arrays-dynamic-ui-guide-1024x1024.png\" alt=\"Next.js Project Progress Tracker showing React components, props, arrays, map, TypeScript, and dynamic progress bars\" class=\"wp-image-1382\" srcset=\"https:\/\/www.projectimmerse.com\/blog\/wp-content\/uploads\/2026\/07\/nextjs-components-props-arrays-dynamic-ui-guide-1024x1024.png 1024w, https:\/\/www.projectimmerse.com\/blog\/wp-content\/uploads\/2026\/07\/nextjs-components-props-arrays-dynamic-ui-guide-300x300.png 300w, https:\/\/www.projectimmerse.com\/blog\/wp-content\/uploads\/2026\/07\/nextjs-components-props-arrays-dynamic-ui-guide-150x150.png 150w, https:\/\/www.projectimmerse.com\/blog\/wp-content\/uploads\/2026\/07\/nextjs-components-props-arrays-dynamic-ui-guide-768x768.png 768w, https:\/\/www.projectimmerse.com\/blog\/wp-content\/uploads\/2026\/07\/nextjs-components-props-arrays-dynamic-ui-guide-100x100.png 100w, https:\/\/www.projectimmerse.com\/blog\/wp-content\/uploads\/2026\/07\/nextjs-components-props-arrays-dynamic-ui-guide.png 1254w\" sizes=\"auto, (max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><figcaption class=\"wp-element-caption\">How components, props, arrays, <code>.map()<\/code>, and dynamic data work together in the Next.js Project Progress Tracker.<\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Once the projects were stored in an array, React could generate the cards automatically using <code>.map()<\/code>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\n{projects.map((project) =&gt; (\n  &lt;ProjectCard\n    key={project.title}\n    title={project.title}\n    progress={project.progress}\n    status={project.status}\n  \/&gt;\n))}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Conceptually, this says:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">For every project inside <code>projects<\/code>, create a <code>ProjectCard<\/code> using that project&#8217;s information.<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">If there are two projects, React generates two cards.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If there are ten projects, React generates ten cards.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The component code doesn&#8217;t change.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Understanding <code>project<\/code><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Inside:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\nprojects.map((project) =&gt; (\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\"><code>project<\/code> represents whichever object <code>.map()<\/code> is currently processing.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">During the first iteration:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nproject.title\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">might be:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nPortfolio Website\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">During the next iteration, it might be:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nTracker App\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">React takes those values and passes them into <code>ProjectCard<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That means:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\ntitle={project.title}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">eventually becomes something equivalent to:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\ntitle=&quot;Portfolio Website&quot;\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">for the first project.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Why React Needs a <code>key<\/code><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">There&#8217;s also this:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\nkey={project.title}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">When React renders lists, it needs a unique identifier for each item.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The <code>key<\/code> helps React determine which item changed, was added, or was removed when the list updates.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Using the project title works for this early version because each title is unique.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Later, each project should have an actual ID:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\n{\n  id: 1,\n  title: &quot;Portfolio Website&quot;,\n  progress: 75,\n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Then I could use:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nkey={project.id}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">which is a more reliable approach.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">The Current <code>page.tsx<\/code><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">At this stage, the home page looks like this:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\nimport Header from &quot;@\/components\/Header&quot;;\nimport ProjectCard from &quot;@\/components\/ProjectCard&quot;;\n\nconst projects = &#x5B;\n  {\n    title: &quot;Portfolio Website&quot;,\n    progress: 75,\n    status: &quot;In Progress&quot;,\n  },\n  {\n    title: &quot;Tracker App&quot;,\n    progress: 100,\n    status: &quot;Completed&quot;,\n  },\n];\n\nexport default function Home() {\n  return (\n    &lt;main className=&quot;max-w-4xl mx-auto p-8&quot;&gt;\n      &lt;Header \/&gt;\n\n      {projects.map((project) =&gt; (\n        &lt;ProjectCard\n          key={project.title}\n          title={project.title}\n          progress={project.progress}\n          status={project.status}\n        \/&gt;\n      ))}\n    &lt;\/main&gt;\n  );\n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">It&#8217;s still a small application, but there&#8217;s already a meaningful separation between <strong>data<\/strong> and <strong>presentation<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The array contains the data.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><code>ProjectCard<\/code> determines how a project looks.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><code>page.tsx<\/code> puts everything together.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Adding Dynamic Progress Bars<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The next improvement was visual.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Displaying:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nProgress: 75%\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">works, but a project tracker should probably have an actual progress bar.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Inside <code>ProjectCard<\/code>, I added:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\n&lt;div className=&quot;mt-3 h-3 w-full rounded-full bg-gray-200&quot;&gt;\n  &lt;div\n    className=&quot;h-3 rounded-full bg-blue-600&quot;\n    style={{ width: `${progress}%` }}\n  \/&gt;\n&lt;\/div&gt;\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">The outer <code>&lt;div&gt;<\/code> creates the background track.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The inner <code>&lt;div&gt;<\/code> creates the filled portion.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The interesting part is:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\nstyle={{ width: `${progress}%` }}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">If:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nprogress = 75\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">React effectively produces:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nwidth: &quot;75%&quot;\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">If progress is 30, the bar becomes 30% wide.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If it&#8217;s 100, the entire bar fills.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Understanding the Double Curly Braces<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">At first:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\nstyle={{ width: `${progress}%` }}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">looks like React has started communicating exclusively through punctuation.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">There&#8217;s a reason for both sets of braces.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The outer braces:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nstyle={ }\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">tell JSX that JavaScript is being used.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The inner braces:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n{\n  width: &quot;75%&quot;\n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">represent a JavaScript object.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">So:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nstyle={{ width: `${progress}%` }}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">means:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">Set the <code>style<\/code> prop equal to a JavaScript object whose <code>width<\/code> property is based on the project&#8217;s progress.<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">Once broken apart, it&#8217;s much less intimidating.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Are the Percentages Actually Dynamic?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Sort of.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The progress bars are currently <strong>data-driven<\/strong>, but the underlying data is still hardcoded.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For example:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nprogress: 75\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">automatically controls both:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nProgress: 75%\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">and the width of the progress bar.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Changing it to:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nprogress: 40\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">updates both parts of the interface.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That&#8217;s dynamic rendering.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">However, I still have to edit the source code to change <code>75<\/code> to <code>40<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The application doesn&#8217;t yet allow the user to click something and change the percentage.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That requires another major React concept: <strong>state<\/strong>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Static Data vs. React State<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Right now the application works roughly like this:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nprojects array\n      \u2193\n    .map()\n      \u2193\nProjectCard\n      \u2193\nprogress prop\n      \u2193\nProgress bar\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">The next stage will look more like:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nUser completes milestone\n          \u2193\nReact state changes\n          \u2193\nProgress recalculated\n          \u2193\nComponent re-renders\n          \u2193\nProgress bar updates\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">That&#8217;s when the application will become genuinely interactive.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Eventually, I don&#8217;t want to manually specify:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nprogress: 75\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">at all.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Instead, the app should calculate progress based on completed milestones.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For example, if a project has four milestones:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n\u2713 Planning\n\u2713 Design\n\u2713 Development\n\u25a1 Deployment\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">then three out of four are complete:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n3 \/ 4 = 75%\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">The application can calculate that automatically.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That will make the progress tracker actually track progress rather than politely displaying whatever number I typed into the source code.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Git and GitHub Along the Way<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">I also set up Git and pushed the project to GitHub.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This is something I wanted to incorporate from the beginning rather than waiting until the application was finished.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The basic workflow is:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\ngit status\ngit add .\ngit commit -m &quot;Describe the change&quot;\ngit push\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">The first push used:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\ngit push -u origin main\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">The <code>-u<\/code> option sets the upstream branch.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Essentially, it tells Git:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nlocal main \u2192 origin\/main\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">and asks it to remember that relationship.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">After that, future pushes can simply use:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\ngit push\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">It&#8217;s a small thing, but understanding what Git commands actually do feels considerably better than collecting terminal commands like mysterious incantations.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">What I&#8217;ve Learned So Far<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">This relatively small application has already covered a surprising amount of ground.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I&#8217;ve worked with:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Next.js App Router<\/li>\n\n\n\n<li><code>page.tsx<\/code><\/li>\n\n\n\n<li>JSX<\/li>\n\n\n\n<li>React function components<\/li>\n\n\n\n<li>Component imports and exports<\/li>\n\n\n\n<li>Props<\/li>\n\n\n\n<li>TypeScript prop types<\/li>\n\n\n\n<li>Destructuring<\/li>\n\n\n\n<li>JavaScript arrays<\/li>\n\n\n\n<li>JavaScript objects<\/li>\n\n\n\n<li><code>.map()<\/code><\/li>\n\n\n\n<li>React <code>key<\/code> props<\/li>\n\n\n\n<li>Tailwind CSS<\/li>\n\n\n\n<li>Dynamic inline styles<\/li>\n\n\n\n<li>Template literals<\/li>\n\n\n\n<li>Git<\/li>\n\n\n\n<li>GitHub<\/li>\n\n\n\n<li>SSH authentication<\/li>\n\n\n\n<li>Remote repositories<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">More importantly, these concepts aren&#8217;t being learned independently.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">They&#8217;re starting to connect.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A project exists as an object.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Objects live inside an array.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><code>.map()<\/code> iterates over that array.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Each object gets passed into a reusable component through props.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Those props control what the component displays.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">And changing the data changes the interface.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That&#8217;s starting to reveal the bigger React idea:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>The UI is a representation of the application&#8217;s data.<\/strong><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">What&#8217;s Next for the Project Progress Tracker?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The next major concept is React state with <code>useState<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That&#8217;s where things should get considerably more interesting.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Instead of hardcoded project information, I want users to eventually be able to:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Add a new project.<\/li>\n\n\n\n<li>Define milestones.<\/li>\n\n\n\n<li>Mark milestones as complete.<\/li>\n\n\n\n<li>Automatically calculate project completion percentages.<\/li>\n\n\n\n<li>Edit and delete projects.<\/li>\n\n\n\n<li>Filter active and completed projects.<\/li>\n\n\n\n<li>Save project information between browser sessions.<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">Eventually, the application can move beyond browser storage and use a real database and authentication system.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">But there&#8217;s no reason to sprint there.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">One thing I&#8217;ve already learned from working with Next.js is that understanding the small pieces pays off when they start working together.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Components aren&#8217;t particularly exciting by themselves.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Neither are props.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Neither is <code>.map()<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Put them together, though, and suddenly a small collection of JavaScript objects can generate an entire interface.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">And once state enters the picture, those objects won&#8217;t just generate the interface\u2014they&#8217;ll be able to change it.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That\u2019s where I\u2019m headed next.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Hopefully without breaking everything.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">But this is software development, so no promises.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Learning a new framework is always a little strange at first. You install a bunch of packages, the terminal spits out enough text to make you question your career choices, and suddenly you&#8217;re staring at files with names like page.tsx wondering what exactly you signed up for. That\u2019s where my latest project begins. I\u2019m building &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/www.projectimmerse.com\/blog\/building-my-first-next-js-project-components-props-arrays-and-dynamic-progress-bars\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Building My First Next.js Project: Components, Props, Arrays, and Dynamic Progress Bars&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[56],"tags":[],"class_list":["post-1376","post","type-post","status-publish","format-standard","hentry","category-programming-fundamentals"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.4 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Building My First Next.js Project: Components, Props, Arrays, and Dynamic Progress Bars - Project Immerse<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.projectimmerse.com\/blog\/building-my-first-next-js-project-components-props-arrays-and-dynamic-progress-bars\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Building My First Next.js Project: Components, Props, Arrays, and Dynamic Progress Bars - Project Immerse\" \/>\n<meta property=\"og:description\" content=\"Learning a new framework is always a little strange at first. You install a bunch of packages, the terminal spits out enough text to make you question your career choices, and suddenly you&#8217;re staring at files with names like page.tsx wondering what exactly you signed up for. That\u2019s where my latest project begins. I\u2019m building &hellip; Continue reading &quot;Building My First Next.js Project: Components, Props, Arrays, and Dynamic Progress Bars&quot;\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.projectimmerse.com\/blog\/building-my-first-next-js-project-components-props-arrays-and-dynamic-progress-bars\/\" \/>\n<meta property=\"og:site_name\" content=\"Project Immerse\" \/>\n<meta property=\"article:published_time\" content=\"2026-07-30T05:44:23+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-07-30T19:56:27+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.projectimmerse.com\/blog\/wp-content\/uploads\/2026\/07\/building-first-nextjs-app-components-props-arrays.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1254\" \/>\n\t<meta property=\"og:image:height\" content=\"1254\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Alex Mercer\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Alex Mercer\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"8 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/building-my-first-next-js-project-components-props-arrays-and-dynamic-progress-bars\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/building-my-first-next-js-project-components-props-arrays-and-dynamic-progress-bars\\\/\"},\"author\":{\"name\":\"Alex Mercer\",\"@id\":\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/#\\\/schema\\\/person\\\/c53f2864be524ee6fa08a7e4800dd1e5\"},\"headline\":\"Building My First Next.js Project: Components, Props, Arrays, and Dynamic Progress Bars\",\"datePublished\":\"2026-07-30T05:44:23+00:00\",\"dateModified\":\"2026-07-30T19:56:27+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/building-my-first-next-js-project-components-props-arrays-and-dynamic-progress-bars\\\/\"},\"wordCount\":1736,\"image\":{\"@id\":\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/building-my-first-next-js-project-components-props-arrays-and-dynamic-progress-bars\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/building-first-nextjs-app-components-props-arrays-1024x1024.png\",\"articleSection\":[\"Programming Fundamentals\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/building-my-first-next-js-project-components-props-arrays-and-dynamic-progress-bars\\\/\",\"url\":\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/building-my-first-next-js-project-components-props-arrays-and-dynamic-progress-bars\\\/\",\"name\":\"Building My First Next.js Project: Components, Props, Arrays, and Dynamic Progress Bars - Project Immerse\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/building-my-first-next-js-project-components-props-arrays-and-dynamic-progress-bars\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/building-my-first-next-js-project-components-props-arrays-and-dynamic-progress-bars\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/building-first-nextjs-app-components-props-arrays-1024x1024.png\",\"datePublished\":\"2026-07-30T05:44:23+00:00\",\"dateModified\":\"2026-07-30T19:56:27+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/#\\\/schema\\\/person\\\/c53f2864be524ee6fa08a7e4800dd1e5\"},\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/building-my-first-next-js-project-components-props-arrays-and-dynamic-progress-bars\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/building-my-first-next-js-project-components-props-arrays-and-dynamic-progress-bars\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/building-my-first-next-js-project-components-props-arrays-and-dynamic-progress-bars\\\/#primaryimage\",\"url\":\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/building-first-nextjs-app-components-props-arrays.png\",\"contentUrl\":\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/building-first-nextjs-app-components-props-arrays.png\",\"width\":1254,\"height\":1254},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/building-my-first-next-js-project-components-props-arrays-and-dynamic-progress-bars\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Building My First Next.js Project: Components, Props, Arrays, and Dynamic Progress Bars\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/\",\"name\":\"Project Immerse\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/#\\\/schema\\\/person\\\/c53f2864be524ee6fa08a7e4800dd1e5\",\"name\":\"Alex Mercer\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/09\\\/alex-mercer-author-150x150.png\",\"url\":\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/09\\\/alex-mercer-author-150x150.png\",\"contentUrl\":\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/09\\\/alex-mercer-author-150x150.png\",\"caption\":\"Alex Mercer\"},\"description\":\"Alex Mercer is a writer and contributor at Project Immerse, covering web design, WordPress, web development, SEO, digital strategy, emerging technology, and the evolving world of the web. His work focuses on practical ideas, useful tools, and approachable guidance that help creators, developers, and business owners build better digital experiences. Alex writes with a hands-on, curiosity-driven approach, exploring both established web practices and new technologies shaping how websites are designed, built, and discovered.\",\"sameAs\":[\"https:\\\/\\\/www.projectimmerse.com\"],\"url\":\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/author\\\/projectimmerse\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Building My First Next.js Project: Components, Props, Arrays, and Dynamic Progress Bars - Project Immerse","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.projectimmerse.com\/blog\/building-my-first-next-js-project-components-props-arrays-and-dynamic-progress-bars\/","og_locale":"en_US","og_type":"article","og_title":"Building My First Next.js Project: Components, Props, Arrays, and Dynamic Progress Bars - Project Immerse","og_description":"Learning a new framework is always a little strange at first. You install a bunch of packages, the terminal spits out enough text to make you question your career choices, and suddenly you&#8217;re staring at files with names like page.tsx wondering what exactly you signed up for. That\u2019s where my latest project begins. I\u2019m building &hellip; Continue reading \"Building My First Next.js Project: Components, Props, Arrays, and Dynamic Progress Bars\"","og_url":"https:\/\/www.projectimmerse.com\/blog\/building-my-first-next-js-project-components-props-arrays-and-dynamic-progress-bars\/","og_site_name":"Project Immerse","article_published_time":"2026-07-30T05:44:23+00:00","article_modified_time":"2026-07-30T19:56:27+00:00","og_image":[{"width":1254,"height":1254,"url":"https:\/\/www.projectimmerse.com\/blog\/wp-content\/uploads\/2026\/07\/building-first-nextjs-app-components-props-arrays.png","type":"image\/png"}],"author":"Alex Mercer","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Alex Mercer","Est. reading time":"8 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.projectimmerse.com\/blog\/building-my-first-next-js-project-components-props-arrays-and-dynamic-progress-bars\/#article","isPartOf":{"@id":"https:\/\/www.projectimmerse.com\/blog\/building-my-first-next-js-project-components-props-arrays-and-dynamic-progress-bars\/"},"author":{"name":"Alex Mercer","@id":"https:\/\/www.projectimmerse.com\/blog\/#\/schema\/person\/c53f2864be524ee6fa08a7e4800dd1e5"},"headline":"Building My First Next.js Project: Components, Props, Arrays, and Dynamic Progress Bars","datePublished":"2026-07-30T05:44:23+00:00","dateModified":"2026-07-30T19:56:27+00:00","mainEntityOfPage":{"@id":"https:\/\/www.projectimmerse.com\/blog\/building-my-first-next-js-project-components-props-arrays-and-dynamic-progress-bars\/"},"wordCount":1736,"image":{"@id":"https:\/\/www.projectimmerse.com\/blog\/building-my-first-next-js-project-components-props-arrays-and-dynamic-progress-bars\/#primaryimage"},"thumbnailUrl":"https:\/\/www.projectimmerse.com\/blog\/wp-content\/uploads\/2026\/07\/building-first-nextjs-app-components-props-arrays-1024x1024.png","articleSection":["Programming Fundamentals"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/www.projectimmerse.com\/blog\/building-my-first-next-js-project-components-props-arrays-and-dynamic-progress-bars\/","url":"https:\/\/www.projectimmerse.com\/blog\/building-my-first-next-js-project-components-props-arrays-and-dynamic-progress-bars\/","name":"Building My First Next.js Project: Components, Props, Arrays, and Dynamic Progress Bars - Project Immerse","isPartOf":{"@id":"https:\/\/www.projectimmerse.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.projectimmerse.com\/blog\/building-my-first-next-js-project-components-props-arrays-and-dynamic-progress-bars\/#primaryimage"},"image":{"@id":"https:\/\/www.projectimmerse.com\/blog\/building-my-first-next-js-project-components-props-arrays-and-dynamic-progress-bars\/#primaryimage"},"thumbnailUrl":"https:\/\/www.projectimmerse.com\/blog\/wp-content\/uploads\/2026\/07\/building-first-nextjs-app-components-props-arrays-1024x1024.png","datePublished":"2026-07-30T05:44:23+00:00","dateModified":"2026-07-30T19:56:27+00:00","author":{"@id":"https:\/\/www.projectimmerse.com\/blog\/#\/schema\/person\/c53f2864be524ee6fa08a7e4800dd1e5"},"breadcrumb":{"@id":"https:\/\/www.projectimmerse.com\/blog\/building-my-first-next-js-project-components-props-arrays-and-dynamic-progress-bars\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.projectimmerse.com\/blog\/building-my-first-next-js-project-components-props-arrays-and-dynamic-progress-bars\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.projectimmerse.com\/blog\/building-my-first-next-js-project-components-props-arrays-and-dynamic-progress-bars\/#primaryimage","url":"https:\/\/www.projectimmerse.com\/blog\/wp-content\/uploads\/2026\/07\/building-first-nextjs-app-components-props-arrays.png","contentUrl":"https:\/\/www.projectimmerse.com\/blog\/wp-content\/uploads\/2026\/07\/building-first-nextjs-app-components-props-arrays.png","width":1254,"height":1254},{"@type":"BreadcrumbList","@id":"https:\/\/www.projectimmerse.com\/blog\/building-my-first-next-js-project-components-props-arrays-and-dynamic-progress-bars\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.projectimmerse.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Building My First Next.js Project: Components, Props, Arrays, and Dynamic Progress Bars"}]},{"@type":"WebSite","@id":"https:\/\/www.projectimmerse.com\/blog\/#website","url":"https:\/\/www.projectimmerse.com\/blog\/","name":"Project Immerse","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.projectimmerse.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.projectimmerse.com\/blog\/#\/schema\/person\/c53f2864be524ee6fa08a7e4800dd1e5","name":"Alex Mercer","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.projectimmerse.com\/blog\/wp-content\/uploads\/2026\/09\/alex-mercer-author-150x150.png","url":"https:\/\/www.projectimmerse.com\/blog\/wp-content\/uploads\/2026\/09\/alex-mercer-author-150x150.png","contentUrl":"https:\/\/www.projectimmerse.com\/blog\/wp-content\/uploads\/2026\/09\/alex-mercer-author-150x150.png","caption":"Alex Mercer"},"description":"Alex Mercer is a writer and contributor at Project Immerse, covering web design, WordPress, web development, SEO, digital strategy, emerging technology, and the evolving world of the web. His work focuses on practical ideas, useful tools, and approachable guidance that help creators, developers, and business owners build better digital experiences. Alex writes with a hands-on, curiosity-driven approach, exploring both established web practices and new technologies shaping how websites are designed, built, and discovered.","sameAs":["https:\/\/www.projectimmerse.com"],"url":"https:\/\/www.projectimmerse.com\/blog\/author\/projectimmerse\/"}]}},"_links":{"self":[{"href":"https:\/\/www.projectimmerse.com\/blog\/wp-json\/wp\/v2\/posts\/1376","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.projectimmerse.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.projectimmerse.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.projectimmerse.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.projectimmerse.com\/blog\/wp-json\/wp\/v2\/comments?post=1376"}],"version-history":[{"count":7,"href":"https:\/\/www.projectimmerse.com\/blog\/wp-json\/wp\/v2\/posts\/1376\/revisions"}],"predecessor-version":[{"id":1388,"href":"https:\/\/www.projectimmerse.com\/blog\/wp-json\/wp\/v2\/posts\/1376\/revisions\/1388"}],"wp:attachment":[{"href":"https:\/\/www.projectimmerse.com\/blog\/wp-json\/wp\/v2\/media?parent=1376"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.projectimmerse.com\/blog\/wp-json\/wp\/v2\/categories?post=1376"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.projectimmerse.com\/blog\/wp-json\/wp\/v2\/tags?post=1376"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}