kieranroberts.dev: My New Dev Portfolio Built With Astro, TailwindCSS, and TypeScript


I wanted to build a new personal developer portfolio for myself. Somewhere to showcase my skills, experience, projects etc. It is now deployed at kieranroberts.dev and I wanted to write up a small case study reflecting on the project. Talk about what went well, what I might do differently next time, and what can be improved. I will also discuss the tech involved and the thinking behind certain decisions.
I’ve had my eye on Astro for a while, knowing it would be a perfect fit for a simple content-focused site like this. Leveraging TailwindCSS, TypeScript, and Hashnode API’s for the remaining work, here is a look behind the curtain of my new portfolio and how it was put together.
The ‘final’ product
I’m hesitant to say ‘final’ since it will be iterated on further, but we can say the initial MVP is done:
The problem
This a list of notes/requirements I kept in mind before beginning the project:
I will be a simple content focused site and minimal dynamic elements.
Start out as a simple one-pager.
Fast.
Accessible.
Be search engine optimised.
Clean/simple design style to not get bogged down in design hell.
Light/dark theme.
Free hosting.
Site content
The page would have the following sections at a minimum:
Landing page hero.
Career & experience (relevant stuff only with CV download).
Blog (recent articles only and a link to the blog).
Testimonials
Personal projects.
Additional achievements.
With that mind, it was time to pick the right tools for the job.
Tech stack
Astro
kieranroberts.dev/blog
, Astro would be a great fit for this use case as well so future-proofing is covered.TailwindCSS
Hashnode GraphQL API’s
fetch
but I like opting for this when working with GraphQL. It makes no significant difference to the bundle size here and I anticipate more data fetching in the future.TypeScript
Cloudflare Pages
The approach
There weren’t any technical challenges with this project so the primary focus was on the UI/UX and delivering a fast and accessible experience.
How was the Astro experience
This was my first project building with Astro. Overall it was a pleasant experience. The docs are great and adapting to Astro was straightforward. At first I was experimenting using React alongside Astro which is viable with the help of Astro client directives. But I quickly realised React is overkill here. I wanted to take advantage of astro components .astro
as they render to static HTML without client-side runtime, and so I converted any straggling React into Astro files and removed the React dependencies altogether.
An example of this was a light/dark theme toggle. Initially I wrote this in React but it was simply wasn’t needed and therefore I refactored to plain TypeScript:
// ThemeToggle.astro
---
import { Icon } from 'astro-icon/components';
---
<script>
import { Themes, THEME_STORAGE_KEY } from '../consts/index';
import type { Theme } from '../env';
const button = document.getElementById('theme-toggle');
const theme = (() => {
if (typeof localStorage !== 'undefined' && localStorage.getItem(THEME_STORAGE_KEY)) {
return (localStorage.getItem(THEME_STORAGE_KEY) as Theme) || Themes.light;
}
return window.matchMedia('(prefers-color-scheme: dark)').matches ? Themes.dark : Themes.light;
})();
const reflectThemePreference = (theme: Theme) => {
document.documentElement.className = '';
document.documentElement.classList.add(theme);
button?.setAttribute('aria-label', `${theme} theme`);
};
reflectThemePreference(theme);
window.localStorage.setItem(THEME_STORAGE_KEY, theme);
const handleToggleClick = () => {
const element = document.documentElement;
const newTheme = element.classList.contains('dark') ? Themes.light : Themes.dark;
reflectThemePreference(newTheme);
localStorage.setItem(THEME_STORAGE_KEY, newTheme);
};
button?.addEventListener('click', handleToggleClick);
</script>
<button
id="theme-toggle"
title="Toggles light & dark theme"
class="group flex items-center justify-center rounded-full p-1.5"
>
<span
class="duration-400 block text-zinc-900 transition-transform ease-in-out group-hover:-rotate-90 dark:text-zinc-50"
>
<Icon name="sun" class="block dark:hidden" width="24" height="24" />
<Icon name="moon" class="hidden dark:block" width="24" height="24" />
</span>
</button>
Removing the React code and dependencies helped reduce the bundle size and ensured I was taking advantage of what Astro offers.
I’m sure as the project grows there will opportunities to explore some of the latest Astro features like Astro Server Islands architecture.
Design overview
Design is usually the tricky part for me. It’s easy to start experimenting too early and lose time to ideas that didn’t work out. This time I was determined to keep things simple at first and then slowly add extra layers over time.
Because I was not attempting complex design from the start, I decided to skip pre-designing the page in Figma. This is something I have done in the past for small side projects and it helped. But on this occasion I wanted to get my ideas into code as soon as possible.
Every site needs a button
One of the earliest things I did was create a simple button
component with a couple variants. To add some polish I utilised CSS transitions and icon slots. The button is one of the first things you notice on a site, and usually what you click first so I wanted to design a nice version.
Navbar UX
Recently I wrote an article on a specific type of UX for a main site navigation and I decided to opt for this behavior on my portfolio. You can find a tutorial on this with more information here:
Color scheme
It’s easy to find a good color scheme. There are countless free tools to help you pick a pre-defined theme. I wanted my primary theme colors to be simple white/dark/gray to keep a clean and modern look. On top of that I added some accent colors to the tailwind config that added a bit more life to the site. They would help bring some ‘pop’ to elements in areas such as focus styling, icons, and background sections.
'accent-darkest': '#6F61C0',
'accent-dark': '#A084E8',
'accent-bright': '#8BE8E5',
'accent-brightest': '#D5FFE4',
Icons
As far as Icons go, I opted to keep a local copy of icons I would use in the repo using /src/icons
, saving each icon as a .svg
. There is a package called astro-icon that helps simplify working with icons in Astro projects, this handles embedding the icon.
As far as the icons themselves I opted for icons from the open source project iconoir. Largely because of the simple one click copy of the svg code and the large free set of icons available.
If I ever decide to update icons in the future, changing one icon at a time can be easily done.
Once those design decisions were made, most of the blockers to writing up core code was done and I could proceed with the build.
Outcome
What went well
Overall I am happy with the outcome. The site feels fast thanks to the lack of JavaScript and server first approach of Astro. It scores well across Lighthouse scores which admittedly should be the minimum standard for a site like this.
There was some trial and error with the design but I didn’t get stuck iterating on anything for too long. There’s always room for iteration and improvement. I am not a designer but I was able to harness some inspiration and tips from my experience working with a talented design team. An example is that I paid closer attention to text colors/weights than I would have previously, layering in different shades & weights where appropriate.
What would I do differently next time
I would have avoided beginning the project with React and Astro, and just started with Astro. I had written some components in React initially but soon realised it wasn’t necessary. Likely that since I had been working with React for so long, it was strange to separate initially.
What can be improved
Image handling
src/images
where Astro optimises and bundles them. There is likely further optimisation that could be done here.Content
Automate showing new articles
There are further minor improvements I intend to make to various sections as well.
Summary
I recently built a new personal developer portfolio for myself using Astro, TailwindCSS, and TypeScript ensuring a fast, accessible site with great SEO. The project focused on simplicity, speed, and clean design and the case study helped me contextualise the project and seek ways to improve. It was a lot of fun to build and I’m excited about all the things I can add and improve upon in the future.
Thanks for reading!
Subscribe to my newsletter
Read articles from Kieran Roberts directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
