Developer Portfolio with Charts
Build a live portfolio site with interactive contribution charts using Chart.js.
Introduction
30 Second Summary
Every developer needs a way to show off their work. A portfolio with live data visualizations says more about your skills than a plain list of technologies ever could.
In this project, you will build a developer portfolio website with interactive charts that visualize your coding contribution data. You will deploy it live to GitHub Pages so anyone can visit your site at your own URL.
What You'll Build
When you share your portfolio link, visitors see an animated dashboard where bar and line charts spring to life showing your weekly commit patterns and yearly contribution trends.
By the end of this project, you'll have:
- A live portfolio website at your own GitHub Pages URL, complete with a hero section and project gallery you can show anyone.
- An animated bar chart built with Chart.js showing your weekly commit breakdown by day of the week.
- A smooth line chart visualizing your contribution trend over 12 months, with hover tooltips and responsive sizing on any screen.
- Secret Mission: Add an interactive radar chart showing your proficiency across different programming languages and technologies.
Are there any prerequisites?
This project assumes familiarity with HTML, CSS, and JavaScript. You will also need a GitHub account and a code editor like VS Code or Cursor.
Before We Start
Before we dive in, let's lock in what you're about to build and why it matters. Taking a moment to commit to the goal gives you a clear finish line to work toward.
Set Up Your Repository and Get a Page Live
Before you can build a portfolio anyone can visit, you need a home for it on the internet. GitHub Pages turns any GitHub repository into a live website at a public URL, for free.
In this step, you will create a repository, push a minimal page to it, and enable GitHub Pages so you have a working deployment pipeline from the very first commit.
In this step, get ready to:
- Create a GitHub repository and clone it to your computer.
- Add a minimal HTML page and push it to GitHub.
- Enable GitHub Pages and confirm your site is live on the internet.
Create your GitHub repository
Your portfolio needs a Git repository to store the code and connect to GitHub Pages.
- Navigate to github.com in your browser.
- In the upper-right corner, click the + icon.
- Select New repository.
- Enter portfolio in the Repository name field.
- Select Public.
- Check Add a README file.
- Click Create repository.
GitHub redirects you to your new repository page.
- Click the green Code button on the repository page.
- Make sure the HTTPS tab is selected, then click the copy icon to copy the URL.
Now clone the repository to your Desktop.
- In VS Code, open the integrated terminal by pressing Ctrl+` (macOS and Windows).
- Move to your Desktop by running this command:
cd ~/Desktop
- Clone your repository by running this command:
git clone [[REPO_URL="https://github.com/your-username/portfolio.git"]]
- Confirm the folder was created by running:
ls
You should see a portfolio folder listed in the output.
Don't see the portfolio folder?
Double-check that you pasted the correct HTTPS URL from the green Code button.
Make sure you ran cd ~/Desktop first so you are in the right directory.
Help me troubleshoot
Create your project files
Your site needs an index.html file as its entry point. You will also add a special file that tells GitHub Pages to skip its default build tool.
- Move into the cloned folder by running this command:
cd portfolio
- Open this folder in VS Code by clicking File in the top menu bar.
- Click Open Folder.
- Select the portfolio folder on your Desktop, then click Open.
- In the Explorer sidebar on the left, click the New File icon (a page with a plus sign).
- Name the file index.html and press Enter.
- Paste the following HTML into the file:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hello World</title>
</head>
<body>
<h1>Hello World</h1>
</body>
</html>
What does this code do?
- <!DOCTYPE html> tells the browser this is a modern HTML5 page.
- The <meta name="viewport"> tag ensures the page scales properly on mobile devices.
- <h1>Hello World</h1> places a large heading on the page so you have something visible to confirm deployment works.
- Save index.html by pressing Cmd+S (macOS) or Ctrl+S (Windows).
Now create the .nojekyll file. This empty file tells GitHub Pages to skip its default Jekyll build process and serve your files directly.
- Open the integrated terminal in VS Code by pressing Ctrl+`.
- Create the file by running this command:
touch .nojekyll
- Confirm both files exist by running:
ls -a
You should see index.html and .nojekyll in the output (the -a flag shows hidden files that start with a dot).
Why do you need a .nojekyll file?
GitHub Pages runs Jekyll by default, which can ignore certain files or add processing you do not want.
The empty .nojekyll file disables this behavior so your HTML, CSS, and JavaScript are served exactly as written.
✔️ Awesome, I've got everything!
Great. Double check you have saved index.html before continuing.
ⓧ I'd like to double check the full code
Your index.html should look exactly like this:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hello World</title>
</head>
<body>
<h1>Hello World</h1>
</body>
</html>
Your .nojekyll file should exist and be completely empty (no content inside).
Push to GitHub and enable Pages
Your files are ready locally. Now you need to push them to GitHub so Pages can serve them.
- Stage, commit, and push your files by running these commands:
git add .
git commit -m "Add index.html and .nojekyll"
git push
What do these commands do?
- git add . stages all new and changed files for the next commit.
- git commit -m saves a snapshot of the staged changes with a message describing what you did.
- git push uploads your commit to GitHub so it is available on the remote repository.
You should see output confirming the push was successful (lines mentioning your branch and object counts).
Push failed or asking for credentials?
If Git asks for a username and password, GitHub no longer accepts passwords for HTTPS. Set up a personal access token or use SSH instead.
If you see a "not a git repository" error, make sure your terminal is inside the portfolio folder. Run cd ~/Desktop/portfolio and try again.
Help me fix my git push error
Now enable GitHub Pages so the repository becomes a live website.
- Go to your portfolio repository on github.com.
- Click the Settings tab near the top of the page.
- In the left sidebar under "Code and automation", click Pages.
- Under "Build and deployment", find the Source dropdown and select Deploy from a branch.
- In the Branch dropdown below, select main.
- Leave the folder set to / (root).
- Click Save.
What is GitHub Pages?
GitHub Pages is a free hosting service that publishes static files from a repository. Every time you push to main, Pages automatically rebuilds and deploys your site within minutes.
Wait 1-2 minutes for GitHub to build and deploy your site. Before you check, what do you expect to see when you visit the URL?
- Open a new browser tab and visit your Pages URL:
[[PAGES_URL="https://your-username.github.io/portfolio"]]
You should see your "Hello World" heading displayed on a live web page.
Seeing a 404 page?
GitHub Pages can take up to 10 minutes to deploy for the first time. Wait a few minutes and refresh.
Confirm you saved index.html in the root of the repository (not inside a subfolder). Check the repository on github.com to verify the file appears at the top level.
Make sure the Branch dropdown on the Pages settings page shows main and the folder shows / (root).
Help me fix my 404 error
Your site is live on the internet. Next up, you will replace this placeholder with a real portfolio layout that has a hero section, project cards, and professional styling.
Build the Portfolio Layout
Your site is live on the internet, but a bare "Hello World" heading is not a portfolio anyone would remember.
In this step, you'll replace that placeholder with a proper portfolio structure and style it with a dark color scheme, responsive grid, and hover effects. Then you'll push the changes and prove the development workflow works end to end.
In this step, get ready to:
- Replace index.html with a full portfolio structure including navigation, hero section, and project cards.
- Create style.css with a dark color scheme, responsive grid layout, and hover effects.
- Push changes to GitHub and verify the styled site is live.
Replace the HTML with your portfolio structure
Your current index.html has a single heading. You'll replace it with a full page structure: a fixed navigation bar, a full-screen hero section, and a grid of project cards.
- In VS Code, open index.html from the Explorer sidebar.
- Select all the existing content (Cmd+A on macOS or Ctrl+A on Windows) and delete it.
- Paste the following code, which sets up the document head, a navigation header, and the hero section:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Bindhu Gadham - Developer Portfolio</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<header>
<nav>
<a href="#hero" class="logo">BG</a>
<ul>
<li><a href="#projects">Projects</a></li>
<li><a href="#stats">Stats</a></li>
</ul>
</nav>
</header>
<section id="hero">
<h1>Hi, I'm <span class="highlight">Bindhu Gadham</span></h1>
<p>Full-stack developer building tools that solve real problems.</p>
</section>
What does this code do?
The <head> links to a stylesheet you'll create next. The <header> creates a navigation bar with a logo and anchor links that scroll to page sections.
The <section id="hero"> is a full-screen introduction with your name and a one-line tagline. The highlight class will style your name with a different color.
- Directly below the hero section's closing </section> tag, add the projects section, footer, and closing tags:
<section id="projects">
<h2>Projects</h2>
<div class="projects-grid">
<div class="project-card">
<h3>Project One</h3>
<p>A web app that helps teams track their daily standups and blockers.</p>
<a href="#" class="project-link">View Project</a>
</div>
<div class="project-card">
<h3>Project Two</h3>
<p>CLI tool for batch-resizing images with smart cropping.</p>
<a href="#" class="project-link">View Project</a>
</div>
<div class="project-card">
<h3>Project Three</h3>
<p>Real-time dashboard for monitoring API response times.</p>
<a href="#" class="project-link">View Project</a>
</div>
</div>
</section>
<footer>
<p>Built with HTML, CSS, and Chart.js. Hosted on GitHub Pages.</p>
</footer>
</body>
</html>
What does this code do?
The .projects-grid container holds three .project-card divs. Each card has a title, description, and a link. You'll style these into a responsive grid shortly.
The <footer> wraps up the page with a credit line.
- Save index.html.
- Open the file directly in your browser (right-click the file in VS Code's Explorer, select Reveal in Finder or Reveal in File Explorer, then double-click index.html).
You should see unstyled text content: a navigation list, your name and tagline, three project titles with descriptions, and the footer text. It looks plain because the stylesheet does not exist yet.
Seeing a blank page?
Check that you pasted both code blocks in order. The second block starts right after the first hero </section> tag. Also confirm the file ends with </body></html>.
Still stuck? Help me debug why my index.html shows a blank page in the browser.
Style the page with a dark theme and layout
Unstyled HTML is just a wall of text. You'll create style.css and build up the dark color scheme, fixed nav, and responsive grid piece by piece.
- In VS Code, create a new file called style.css in the same folder as index.html (click the new file icon in the Explorer sidebar).
- Add the global reset, body styles, and navigation layout by pasting this code:
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background-color: #0d1117;
color: #e6edf3;
line-height: 1.6;
}
header {
position: fixed;
top: 0;
width: 100%;
background-color: #161b22;
border-bottom: 1px solid #30363d;
z-index: 100;
}
nav {
max-width: 1200px;
margin: 0 auto;
padding: 1rem 2rem;
display: flex;
justify-content: space-between;
align-items: center;
}
What does this code do?
The * selector removes default browser margins and padding. box-sizing: border-box makes width calculations include padding and borders.
The body gets a dark background (#0d1117) with light text. The header is position: fixed so it stays visible when scrolling. The nav uses Flexbox to space the logo and links apart.
- Below the nav block, add the logo, navigation links, and base section styles:
.logo {
font-size: 1.5rem;
font-weight: 700;
color: #58a6ff;
text-decoration: none;
}
nav ul {
display: flex;
list-style: none;
gap: 2rem;
}
nav ul a {
color: #e6edf3;
text-decoration: none;
transition: color 0.2s;
}
nav ul a:hover {
color: #58a6ff;
}
section {
max-width: 1200px;
margin: 0 auto;
padding: 6rem 2rem;
}
What does this code do?
The .logo gets a blue accent color (#58a6ff). Navigation links transition smoothly to blue on hover. The base section rule constrains content width and adds generous padding.
- Save style.css and refresh your browser tab showing index.html.
You should see a dark page with a fixed navigation bar at the top showing "BG" on the left and "Projects" / "Stats" links on the right.
Still seeing unstyled text?
Make sure style.css is saved in the same folder as index.html. Check that your HTML <head> contains <link rel="stylesheet" href="style.css"> exactly.
Need help? My style.css isn't being applied to my HTML page.
- Back in style.css, add the hero section and section heading styles below your existing code:
#hero {
min-height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
text-align: center;
padding-top: 80px;
}
#hero h1 {
font-size: 3rem;
margin-bottom: 1rem;
}
.highlight {
color: #58a6ff;
}
#hero p {
font-size: 1.25rem;
color: #8b949e;
max-width: 600px;
}
#projects h2,
#stats h2 {
font-size: 2rem;
margin-bottom: 2rem;
text-align: center;
}
What does this code do?
The hero section uses Flexbox to center its content both vertically and horizontally, taking up the full viewport height (min-height: 100vh). The padding-top: 80px prevents content from hiding behind the fixed header.
The .highlight class turns your name blue. The tagline paragraph gets a muted gray color so it feels secondary to the heading.
- Save style.css and refresh the browser.
Your hero section now fills the screen with your name centered in large text, "Bindhu Gadham" highlighted in blue, and the tagline below in gray.
- Add the project card grid styles below your existing code in style.css:
.projects-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 1.5rem;
}
.project-card {
background-color: #161b22;
border: 1px solid #30363d;
border-radius: 8px;
padding: 2rem;
transition: border-color 0.2s, transform 0.2s;
}
.project-card:hover {
border-color: #58a6ff;
transform: translateY(-2px);
}
.project-card h3 {
margin-bottom: 0.75rem;
color: #e6edf3;
}
.project-card p {
color: #8b949e;
margin-bottom: 1rem;
}
What does this code do?
The .projects-grid uses CSS Grid with auto-fit and minmax(280px, 1fr) to create a responsive layout. Cards fill 3 columns on wide screens and collapse to 1 column on mobile, with no media query needed for that behavior.
Each card gets a subtle border and lifts slightly on hover via transform: translateY(-2px). The transition makes both the border color change and the lift feel smooth.
- Add the final styles for project links, the footer, and mobile responsiveness:
.project-link {
color: #58a6ff;
text-decoration: none;
font-weight: 500;
}
.project-link:hover {
text-decoration: underline;
}
footer {
text-align: center;
padding: 2rem;
color: #8b949e;
border-top: 1px solid #30363d;
}
@media (max-width: 768px) {
#hero h1 {
font-size: 2rem;
}
nav ul {
gap: 1rem;
}
section {
padding: 4rem 1rem;
}
}
What does this code do?
Project links use the same blue accent color and underline on hover. The footer gets a top border to visually separate it from content above.
The @media query kicks in below 768px to shrink the hero heading, tighten navigation spacing, and reduce section padding for smaller screens.
- Save style.css and refresh the browser.
You should see the full styled portfolio: a dark page with a fixed nav bar, a centered hero section filling the viewport, and a grid of three project cards below with hover effects.
Cards showing in a single column on a wide screen?
Make sure your grid-template-columns value is exactly repeat(auto-fit, minmax(280px, 1fr)). A typo in auto-fit or minmax silently breaks the grid into a single column.
Still stuck? My CSS Grid is not creating multiple columns for my project cards.
✔️ Awesome, I've got everything!
Great. Double check you've saved both index.html and style.css before moving on.
ⓧ I'd like to double check the full code
Scroll up and confirm each section is present in order:
- index.html: Document head with stylesheet link, <header> with nav, <section id="hero">, <section id="projects"> with three cards, and <footer>.
- style.css: Global reset, body and header/nav styles, logo and nav link styles, hero section Flexbox, project card Grid, project links, footer, and the @media query for mobile.
Push to GitHub and verify the live site
Your portfolio looks great locally. Now push the changes so the live GitHub Pages site updates for anyone to see.
- Open your terminal in VS Code (Ctrl+` on both macOS and Windows).
- Stage, commit, and push your changes by running these commands:
git add .
git commit -m "Add portfolio layout and styles"
git push origin main
What do these commands do?
The git add . stages all changed files. The git commit saves a snapshot with a descriptive message. The git push sends everything to GitHub, which triggers a Pages rebuild automatically.
- Wait 1-2 minutes for GitHub Pages to rebuild.
Before you check the live site, what do you expect to see at your Pages URL?
- Visit your live site at https://your-username.github.io/portfolio and refresh the page.
You should see your styled portfolio with the dark background, centered hero section with your name, and three project cards in a grid below.
Still seeing Hello World?
GitHub Pages can take up to 10 minutes to propagate changes. Try a hard refresh (Cmd+Shift+R on macOS or Ctrl+Shift+R on Windows) to bypass your browser cache.
If changes still don't appear, confirm your push succeeded by checking the repository on github.com. You should see style.css listed alongside index.html.
Still stuck? My GitHub Pages site is not updating after I pushed new code.
Your portfolio has real structure and style. Next up, you'll add an interactive data visualization section with Chart.js to make it truly stand out.
Add a Contribution Bar Chart
Your portfolio has a clean layout, but static text and project cards are what every developer site looks like. A data visualization section sets yours apart by proving you can build something dynamic and data-rich.
In this step, you will add Chart.js to your page and create an animated bar chart showing your weekly commit pattern. There is a common sizing gotcha with Chart.js canvases that will surface by the end of this step.
In this step, get ready to:
- Add the Chart.js library and a stats section to your HTML.
- Create a bar chart showing your daily commit activity.
- Observe the canvas sizing behavior that needs fixing.
Add Chart.js and the stats section to your HTML
Chart.js is a library that draws charts on HTML5 <canvas> elements. You need to load the library, create a canvas to draw on, and give it a home in your page.
- In index.html, find the closing </section> tag of your projects section (right before <footer>).
- Add this new stats section between the projects closing tag and the footer:
<!-- Data visualization section -->
<section id="stats">
<h2>Contribution Stats</h2>
<canvas id="commitsChart"></canvas>
</section>
- Now scroll to the bottom of the file. Find the closing </footer> tag.
- Add these two script tags between </footer> and </body>:
<!-- Chart.js library and our chart script -->
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.5.1"></script>
<script src="script.js"></script>
What does this code do?
The <section id="stats"> creates a new page section for your charts. The <canvas> element is where Chart.js will draw the bar chart.
The first script tag loads Chart.js from a CDN. The second loads your own script.js file where you will write the chart code. Order matters here. Your script must come after the library so it can use Chart.
- Save index.html.
- Open index.html in your browser (double-click the file or drag it into a browser tab). You should see the "Contribution Stats" heading below your project cards.
Don't see the heading?
- Make sure the new section is placed before <footer>, not after it.
- Check for unclosed tags. Each <section> needs a matching </section>.
Why isn't my stats section showing up in the browser?
Create the bar chart script
Chart.js creates charts by passing a canvas element and a configuration object to new Chart(). The configuration describes the chart type, the data to plot, and any styling options.
- Create a new file called script.js in the same folder as your index.html.
- Add the chart data structure by pasting this code:
// Get the canvas element for the bar chart
const commitsCtx = document.getElementById('commitsChart');
// Create a bar chart with weekly commit data
const commitsChart = new Chart(commitsCtx, {
type: 'bar',
data: {
labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
datasets: [{
label: 'Commits',
data: [4, 7, 5, 8, 12, 3, 1],
backgroundColor: 'rgba(88, 166, 255, 0.7)',
borderColor: 'rgba(88, 166, 255, 1)',
borderWidth: 1,
borderRadius: 4
}]
},
});
What does this code do?
- commitsCtx grabs the <canvas> element from your HTML so Chart.js knows where to draw.
- type: 'bar' tells Chart.js to render a bar chart.
- labels sets the x-axis categories (days of the week). data provides the height of each bar.
- borderRadius: 4 rounds the top corners of each bar for a polished look.
- Save script.js and refresh your browser.
- You should see a bar chart appear with blue bars. The legend text and axis labels will be dark (hard to read against your dark background). You will fix that next.
No chart appearing?
- Open your browser's developer console (Cmd+Option+J on macOS, Ctrl+Shift+J on Windows). Look for error messages.
- If you see "Chart is not defined", your script tag order is wrong. The Chart.js CDN script must come before script.js.
- If you see "Cannot read properties of null", the canvas ID in your JavaScript (commitsChart) does not match the ID in your HTML.
Help me figure out why my Chart.js bar chart is not rendering.
The chart renders, but the legend and axis labels are dark text on a dark background. Add styling options to match your page theme.
- In script.js, find the closing }); at the bottom of your file.
- Replace it with this options block to style the chart for your dark theme:
// Style chart text and grid to match the dark theme
options: {
plugins: {
legend: {
labels: {
color: '#e6edf3'
}
}
},
scales: {
x: {
ticks: { color: '#8b949e' },
grid: { color: '#30363d' }
},
y: {
beginAtZero: true,
ticks: { color: '#8b949e' },
grid: { color: '#30363d' }
}
}
}
});
What does this code do?
- plugins.legend.labels.color sets the legend text to light gray so it is readable on the dark background.
- ticks.color changes the axis label text to a muted gray.
- grid.color sets the chart gridlines to a subtle dark tone that blends with your page.
- beginAtZero: true ensures the y-axis starts at zero so bar heights are visually proportional.
- Save script.js and refresh your browser.
- The legend text, axis labels, and gridlines now match your dark color scheme. The bars are blue and the chart is readable.
Still seeing dark text on the axes?
- Make sure you replaced the old }); and did not accidentally duplicate it. You should have only one }); at the very end of the file.
- Check that the options key sits inside the same object as type and data, separated by commas.
Help me fix my Chart.js options configuration.
Push and observe the chart sizing
Your chart works and matches the dark theme. Before you push, take a close look at how much vertical space the chart takes up on the page.
- Push your changes to GitHub by running these commands:
git add .
git commit -m "Add contribution bar chart"
git push origin main
Before you reload your live site, predict: do you think the chart will fit neatly within the stats section, or will it dominate the page?
- Wait 1-2 minutes for GitHub Pages to deploy, then reload your live site at https://your-username.github.io/portfolio.
The bar chart renders and animates in. But scroll down to the stats section and notice: the chart stretches to fill the entire section width and is unexpectedly tall. It dominates the page instead of sitting in a compact, contained area.
Why is the chart so large?
Chart.js canvases expand to fill their parent container. Your canvas sits directly inside the <section> element, which spans the full 1200px content width. With no constrained parent, Chart.js maintains a 2:1 aspect ratio against that width, making the chart roughly 600px tall.
This is the most common Chart.js beginner mistake. The fix is to wrap the canvas in a container with explicit dimensions. You will solve this in the next step.
✔️ Awesome, I've got everything!
Great. Double check you have saved both index.html and script.js.
ⓧ I'd like to double check the full code
Your index.html and script.js are longer than a quick glance, so confirm each section is present by scrolling through your files:
- In index.html: the <section id="stats"> block with a <canvas id="commitsChart"> is between the projects section and the footer.
- In index.html: the Chart.js CDN script (chart.js@4.5.1) and script.js link appear between </footer> and </body>.
- In script.js: the commitsCtx variable grabs the canvas, followed by the new Chart() call with type: 'bar', a data object with 7 labels and values, and an options object styling legend and scale colors.
Your chart works and proves you can integrate a data visualization library. But that oversized canvas is not portfolio-ready. In the next step, you will fix the responsiveness and add a second chart that tells a richer story about your contributions.
Fix Chart Responsiveness and Add the Trend Line
Your bar chart is live, but it does not respect the layout boundaries of your page. The canvas stretches to fill whatever space it can find because it has no properly sized parent container.
Chart.js requires a dedicated, relatively positioned container around each canvas to control sizing. In this step, you will wrap your canvases in container divs, style them with a fixed height, and add a second line chart showing your contribution trend over time.
In this step, get ready to:
- Wrap each canvas in a container div that constrains its size.
- Style the chart containers with CSS Grid for a responsive two-column layout.
- Add a line chart showing monthly contribution trends alongside your bar chart.
Wrap canvases in container divs
Chart.js uses the parent container of each canvas to determine render and display sizes. The container must be relatively positioned and dedicated to the chart canvas only.
- In index.html, find the stats section that currently has the bare canvas:
<section id="stats">
<h2>Contribution Stats</h2>
<canvas id="commitsChart"></canvas>
</section>
- Replace everything between the <h2> heading and the closing </section> tag with this structure:
<div class="charts-grid">
<div class="chart-container">
<canvas id="commitsChart"></canvas>
</div>
<div class="chart-container">
<canvas id="trendChart"></canvas>
</div>
</div>
What does this structure do?
Each canvas now lives inside its own .chart-container div. This gives Chart.js a dedicated parent to read sizing from.
The .charts-grid wrapper will become a CSS Grid that places both charts side-by-side. The second canvas (trendChart) is ready for the line chart you will create later in this step.
- Save index.html.
Style the chart containers
The container divs exist, but they have no dimensions yet. Without an explicit height and position: relative, Chart.js still cannot constrain the canvas properly.
- In style.css, add the following rules above the footer styles:
.charts-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
gap: 1.5rem;
}
.chart-container {
position: relative;
height: 300px;
background-color: #161b22;
border: 1px solid #30363d;
border-radius: 8px;
padding: 1.5rem;
}
What do these styles do?
- .charts-grid creates a responsive 2-column grid. On wide screens both charts sit side-by-side. The minmax(400px, 1fr) means each column is at least 400px wide, so they stack to one column on smaller screens.
- .chart-container sets position: relative (required by Chart.js for sizing detection) and a fixed height: 300px so the canvas knows exactly how tall to render.
- Inside the existing @media (max-width: 768px) block at the bottom of the file, add this rule:
.charts-grid {
grid-template-columns: 1fr;
}
- Save style.css and refresh your browser.
- You should see the bar chart now contained inside a dark, bordered card with rounded corners. It is no longer stretching across the full page width.
Chart still stretching or invisible?
- Make sure .chart-container has position: relative. Without it, Chart.js cannot detect size changes on the parent.
- Check that the canvas tag is directly inside the .chart-container div with no extra wrappers between them.
- Confirm you saved both index.html and style.css before refreshing.
Help me debug my chart container styling.
Add the trend line chart and fix aspect ratio
The container is now constraining the chart width, but Chart.js still tries to maintain a 2:1 aspect ratio by default. Setting maintainAspectRatio: false tells Chart.js to fill the container height you defined in CSS instead.
- In script.js, find this line inside the commitsChart options:
options: {
plugins: {
- Add maintainAspectRatio: false, as the first property inside options, so the block now looks like this:
options: {
maintainAspectRatio: false,
plugins: {
- Below the entire commitsChart block (after its closing });), add the trend line chart by pasting this code:
const trendCtx = document.getElementById('trendChart');
const trendChart = new Chart(trendCtx, {
type: 'line',
data: {
labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
datasets: [{
label: 'Contributions',
data: [42, 55, 38, 67, 72, 85, 63, 91, 78, 102, 88, 95],
borderColor: 'rgba(88, 166, 255, 1)',
backgroundColor: 'rgba(88, 166, 255, 0.1)',
fill: true,
tension: 0.4,
pointBackgroundColor: 'rgba(88, 166, 255, 1)',
pointRadius: 3,
pointHoverRadius: 6
}]
},
What does this chart data do?
- type: 'line' creates a line chart instead of a bar chart.
- fill: true fills the area below the line with a subtle transparent blue.
- tension: 0.4 smooths the line into curves instead of sharp angles between data points.
- pointHoverRadius: 6 makes the data points grow larger when a user hovers over them, triggering the tooltip.
- Immediately below the data block you just pasted, add the options and closing bracket:
options: {
maintainAspectRatio: false,
plugins: {
legend: {
labels: {
color: '#e6edf3'
}
}
},
scales: {
x: {
ticks: { color: '#8b949e' },
grid: { color: '#30363d' }
},
y: {
beginAtZero: true,
ticks: { color: '#8b949e' },
grid: { color: '#30363d' }
}
}
}
});
Why the same scale colors?
Both charts share the same dark theme styling for grid lines and tick labels. This creates a cohesive look across the dashboard. The maintainAspectRatio: false setting here ensures the line chart also fills the 300px container height you defined in CSS.
- Save script.js.
Before you push and check the live site, what do you expect to see when you reload the page?
- Push your changes to GitHub by running these commands:
git add .
git commit -m "Fix chart containers and add trend line"
git push
- Wait 1-2 minutes for GitHub Pages to redeploy, then reload your portfolio URL.
You should see two charts sitting side-by-side in dark bordered cards. The bar chart shows daily commits (Mon-Sun). The line chart shows a smooth contribution curve across twelve months with a subtle blue fill beneath it. Hover over any data point and a tooltip appears with the value.
Only seeing one chart or no charts?
- Open your browser's DevTools console (F12 or Cmd+Option+I) and look for JavaScript errors. A missing comma or bracket in script.js will prevent both charts from rendering.
- Make sure the second canvas has id="trendChart" in index.html and that your JavaScript references 'trendChart' with the same spelling.
- Confirm the Chart.js CDN script tag appears before your script.js tag in the HTML.
Help me debug why my Chart.js charts are not rendering.
✔️ Awesome, I've got everything!
Great. Double check you have saved all three files: index.html, style.css, and script.js.
ⓧ I'd like to double check the full code
Scroll up and confirm each of these pieces is present and in order:
- In index.html: the #stats section contains a .charts-grid div wrapping two .chart-container divs, each holding one canvas (commitsChart and trendChart).
- In style.css: .charts-grid uses display: grid with repeat(auto-fit, minmax(400px, 1fr)). .chart-container has position: relative and height: 300px. The media query includes .charts-grid { grid-template-columns: 1fr; }.
- In script.js: both charts have maintainAspectRatio: false in their options. The trend chart uses type: 'line' with 12 months of data, fill: true, and tension: 0.4.
Both charts are rendering cleanly inside their containers. Next up, you will tackle the Secret Mission and add a radar chart showing your skill proficiency across multiple technologies.
Secret mission
Add a Skills Radar Chart
Your portfolio already shows when you code and how often. But what about what you code with? Add a radar chart that maps your proficiency across different technologies, giving visitors an instant visual snapshot of your technical strengths.
Clean Up Your Resources
Clean Up Your Resources
This project runs entirely on GitHub Pages, which is free. Your site will remain live indefinitely at no cost.
Decide whether to keep your resources running, pause them to come back later, or delete them entirely.
Resources you used:
- GitHub repository named portfolio with GitHub Pages enabled.
- Local portfolio folder on your Desktop containing index.html, style.css, script.js, and .nojekyll.
Keep everything running
No action needed. Choose this if you want your portfolio to stay live and accessible at your GitHub Pages URL.
- Your site remains live at your-username.github.io/portfolio for free.
- Push changes to the main branch anytime to update the live site.
- GitHub Pages has no ongoing costs on the free tier.
Pause - I'll come back to this later
Disable the live site while keeping all your code intact. You can re-enable Pages whenever you want to bring the site back online.
- Go to your portfolio repository on GitHub.
- Click Settings in the top navigation.
- Select Pages in the left sidebar under Code and automation.
- Under Build and deployment, change the Source dropdown to None and click Save.
- Your code stays in the repository. Re-enable Pages later by setting the source back to the main branch.
Delete - I don't want to use this again
Remove all project resources completely. This cannot be undone.
- Delete the local project folder by running this command (macOS/Linux):
rm -rf ~/Desktop/portfolio
- On Windows, run this instead:
rmdir /s /q $HOME\Desktop\portfolio
- Delete the GitHub repository by navigating to your portfolio repository on GitHub.
- Click Settings in the top navigation.
- Scroll down to the Danger Zone section at the bottom of the General settings page.
- Click Delete this repository and follow the confirmation prompts.
- This permanently removes the repository, the GitHub Pages site, and all commit history.
That's a Wrap!
That's a Wrap!
Nice work! You just built and deployed a live developer portfolio with an interactive contribution stats dashboard from scratch.
You've learned how to:
- Build a complete portfolio website with vanilla HTML, CSS, and JavaScript, and deploy it live to GitHub Pages at your own URL.
- Create interactive bar and line charts with Chart.js to visualize coding contribution data with animations, tooltips, and hover effects.
- Solve the Chart.js canvas responsiveness problem using positioned container elements with explicit height and maintainAspectRatio: false to constrain charts within a CSS Grid layout.
- Secret Mission: Added a radar chart demonstrating multi-axis data visualization with custom scale configuration.
Ready to quiz yourself?