{"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":[60,57],"tags":[],"class_list":["post-1376","post","type-post","status-publish","format-standard","hentry","category-latest-tech-frameworks","category-web-development"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.1 - 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=\"projectimmerse\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"projectimmerse\" \/>\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\":\"projectimmerse\",\"@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\":[\"Latest Tech &amp; Frameworks\",\"Web Development\"],\"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\":\"projectimmerse\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/4d06955033d6227bfdcf30014e457e4334f7deeb73907de49b65ec2484921931?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/4d06955033d6227bfdcf30014e457e4334f7deeb73907de49b65ec2484921931?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/4d06955033d6227bfdcf30014e457e4334f7deeb73907de49b65ec2484921931?s=96&d=mm&r=g\",\"caption\":\"projectimmerse\"},\"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":"projectimmerse","twitter_card":"summary_large_image","twitter_misc":{"Written by":"projectimmerse","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":"projectimmerse","@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":["Latest Tech &amp; Frameworks","Web Development"],"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":"projectimmerse","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/4d06955033d6227bfdcf30014e457e4334f7deeb73907de49b65ec2484921931?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/4d06955033d6227bfdcf30014e457e4334f7deeb73907de49b65ec2484921931?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/4d06955033d6227bfdcf30014e457e4334f7deeb73907de49b65ec2484921931?s=96&d=mm&r=g","caption":"projectimmerse"},"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}]}}