Build and customize a modern developer/designer portfolio with Next.js, TypeScript, and TailwindCSS featuring animated typing effects and responsive layouts.
Install to Claude Code
npx -y skills add Aradotso/design-skills --skill figma-portfolio-nextjs --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Figma Portfolio Nextjs?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/aradotso-figma-portfolio-nextjs)More formats (shields.io, HTML) on the badges page.
---
name: figma-portfolio-nextjs
description: Build and customize a modern developer/designer portfolio with Next.js, TypeScript, and TailwindCSS featuring animated typing effects and responsive layouts.
triggers:
- create a portfolio website
- build a developer portfolio with nextjs
- customize figma portfolio template
- add projects to portfolio site
- setup personal portfolio with tailwind
- configure nextjs portfolio animations
- deploy portfolio to vercel
- modify portfolio hero section
---
# Figma Portfolio - Next.js Developer Portfolio
> Skill by [ara.so](https://ara.so) — Design Skills collection.
A personal portfolio template for developers and designers, built with Next.js 16, TypeScript, and TailwindCSS. Features a clean dark-themed UI with purple gradient accents, animated typing effects, responsive layouts, and sections to showcase projects, experience, and creative skills.
## Installation
```bash
# Clone the repository
git clone git@github.com:ibrahimmemonn/Figma_Portfolio.git
# Navigate to project directory
cd Figma_Portfolio/
# Install dependencies
npm install
# Run development server
npm run dev
```
The development server starts at `http://localhost:3000`.
## Project Structure
```
Figma_Portfolio/
├── app/
│ ├── page.tsx # Main landing page
│ ├── layout.tsx # Root layout with font config
│ └── globals.css # Global styles with Tailwind
├── components/
│ ├── Hero.tsx # Hero section with typing animation
│ ├── Projects.tsx # Project showcase section
│ ├── Experience.tsx # Experience timeline
│ ├── Skills.tsx # Skills display
│ └── Contact.tsx # Contact section
├── public/
│ ├── projects/ # Project images
│ └── assets/ # Icons and media
└── tailwind.config.ts # Tailwind configuration
```
## Key Features & Configuration
### Font Configuration
The portfolio uses Poppins font optimized with `next/font`:
```typescript
// app/layout.tsx
import { Poppins } from 'next/font/google';
const poppins = Poppins({
subsets: ['latin'],
weight: ['300', '400', '500', '600', '700', '800', '900'],
variable: '--font-poppins',
});
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en" className={poppins.variable}>
<body>{children}</body>
</html>
);
}
```
### Hero Section with Typing Animation
```typescript
// components/Hero.tsx
'use client';
import { useState, useEffect } from 'react';
export default function Hero() {
const [text, setText] = useState('');
const [isDeleting, setIsDeleting] = useState(false);
const [loopNum, setLoopNum] = useState(0);
const [typingSpeed, setTypingSpeed] = useState(150);
const roles = ['Software Engineer', 'UI/UX Designer', 'Full Stack Developer'];
useEffect(() => {
const handleType = () => {
const i = loopNum % roles.length;
const fullText = roles[i];
setText(
isDeleting
? fullText.substring(0, text.length - 1)
: fullText.substring(0, text.length + 1)
);
setTypingSpeed(isDeleting ? 50 : 150);
if (!isDeleting && text === fullText) {
setTimeout(() => setIsDeleting(true), 1000);
} else if (isDeleting && text === '') {
setIsDeleting(false);
setLoopNum(loopNum + 1);
}
};
const timer = setTimeout(handleType, typingSpeed);
return () => clearTimeout(timer);
}, [text, isDeleting, loopNum, typingSpeed, roles]);
return (
<section className="min-h-screen flex items-center justify-center px-4">
<div className="max-w-4xl mx-auto text-center">
<h1 className="text-5xl md:text-7xl font-bold mb-6">
Hi, I'm <span className="bg-gradient-to-r from-purple-400 to-pink-600 bg-clip-text text-transparent">Your Name</span>
</h1>
<h2 className="text-2xl md:text-4xl mb-8">
<span className="text-gray-400">{text}</span>
<span className="animate-pulse">|</span>
</h2>
<p className="text-gray-300 text-lg max-w-2xl mx-auto">
Building digital experiences that combine aesthetic design with powerful functionality.
</p>
</div>
</section>
);
}
```
### Adding Projects
```typescript
// components/Projects.tsx
interface Project {
title: string;
description: string;
image: string;
link: string;
github?: string;
tags: string[];
}
const projects: Project[] = [
{
title: 'E-Commerce Platform',
description: 'Full-stack e-commerce solution with Next.js, Stripe, and MongoDB',
image: '/projects/ecommerce.png',
link: 'https://example.com',
github: 'https://github.com/username/project',
tags: ['Next.js', 'TypeScript', 'Stripe', 'MongoDB'],
},
{
title: 'Portfolio Dashboard',
description: 'Analytics dashboard for tracking portfolio metrics',
image: '/projects/dashboard.png',
link: 'https://example.com',
tags: ['React', 'Chart.js', 'TailwindCSS'],
},
];
export default function Projects() {
return (
<section className="py-20 px-4">
<h2 className="text-4xl font-bold text-center mb-12">
Featured <span className="bg-gradient-to-r from-purple-400 to-pink-600 bg-clip-text text-transparent">Projects</span>
</h2>
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-8 max-w-6xl mx-auto">
{projects.map((project, index) => (
<div key={index} className="bg-gray-800/50 rounded-lg overflow-hidden hover:transform hover:scale-105 transition-all duration-300">
<img src={project.image} alt={project.title} className="w-full h-48 object-cover" />
<div className="p-6">
<h3 className="text-xl font-semibold mb-2">{project.title}</h3>
<p className="text-gray-400 mb-4">{project.description}</p>
<div className="flex flex-wrap gap-2 mb-4">
{project.tags.map((tag, i) => (
<span key={i} className="px-3 py-1 bg-purple-500/20 text-purple-300 rounded-full text-sm">
{tag}
</span>
))}
</div>
<div className="flex gap-4">
<a href={project.link} className="text-purple-400 hover:text-purple-300">
Live Demo →
</a>
{project.github && (
<a href={project.github} className="text-gray-400 hover:text-gray-300">
GitHub →
</a>
)}
</div>
</div>
</div>
))}
</div>
</section>
);
}
```
### Customizing Theme Colors
```typescript
// tailwind.config.ts
import type { Config } from 'tailwindcss';
const config: Config = {
content: [
'./pages/**/*.{js,ts,jsx,tsx,mdx}',
'./components/**/*.{js,ts,jsx,tsx,mdx}',
'./app/**/*.{js,ts,jsx,tsx,mdx}',
],
theme: {
extend: {
colors: {
primary: {
50: '#faf5ff',
100: '#f3e8ff',
500: '#a855f7',
600: '#9333ea',
700: '#7e22ce',
},
},
backgroundImage: {
'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))',
'gradient-conic': 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))',
},
},
},
plugins: [],
};
export default config;
```
### Adding Analytics
```typescript
// app/layout.tsx
import { Analytics } from '@vercel/analytics/react';
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>
{children}
<Analytics />
</body>
</html>
);
}
```
## Deployment
### Deploy to Vercel
```bash
# Install Vercel CLI
npm i -g vercel
# Deploy
vercel
# Deploy to production
vercel --prod
```
Or connect your GitHub repository to Vercel for automatic deployments on every push to `main`.
### Environment Variables
```bash
# .env.local (not committed to git)
NEXT_PUBLIC_SITE_URL=https://your-domain.com
NEXT_PUBLIC_GA_ID=your-google-analytics-id
```
## Common Customization Patterns
### Add a Contact Form
```typescript
// components/Contact.tsx
'use client';
import { useState } from 'react';
export default function Contact() {
const [formData, setFormData] = useState({
name: '',
email: '',
message: '',
});
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
// Integrate with your preferred email service
const response = await fetch('/api/contact', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(formData),
});
if (response.ok) {
alert('Message sent successfully!');
setFormData({ name: '', email: '', message: '' });
}
};
return (
<section className="py-20 px-4">
<div className="max-w-2xl mx-auto">
<h2 className="text-4xl font-bold text-center mb-12">Get In Touch</h2>
<form onSubmit={handleSubmit} className="space-y-6">
<input
type="text"
placeholder="Your Name"
value={formData.name}
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
className="w-full px-4 py-3 bg-gray-800 rounded-lg focus:outline-none focus:ring-2 focus:ring-purple-500"
required
/>
<input
type="email"
placeholder="Your Email"
value={formData.email}
onChange={(e) => setFormData({ ...formData, email: e.target.value })}
className="w-full px-4 py-3 bg-gray-800 rounded-lg focus:outline-none focus:ring-2 focus:ring-purple-500"
required
/>
<textarea
placeholder="Your Message"
value={formData.message}
onChange={(e) => setFormData({ ...formData, message: e.target.value })}
rows={5}
className="w-full px-4 py-3 bg-gray-800 rounded-lg focus:outline-none focus:ring-2 focus:ring-purple-500"
required
/>
<button
type="submit"
className="w-full py-3 bg-gradient-to-r from-purple-500 to-pink-600 rounded-lg font-semibold hover:opacity-90 transition-opacity"
>
Send Message
</button>
</form>
</div>
</section>
);
}
```
### Smooth Scroll Navigation
```typescript
// components/Navigation.tsx
export default function Navigation() {
const scrollToSection = (id: string) => {
const element = document.getElementById(id);
element?.scrollIntoView({ behavior: 'smooth' });
};
return (
<nav className="fixed top-0 w-full bg-gray-900/80 backdrop-blur-sm z-50">
<div className="max-w-6xl mx-auto px-4 py-4 flex justify-between items-center">
<div className="text-xl font-bold">Portfolio</div>
<div className="flex gap-6">
<button onClick={() => scrollToSection('projects')} className="hover:text-purple-400">
Projects
</button>
<button onClick={() => scrollToSection('experience')} className="hover:text-purple-400">
Experience
</button>
<button onClick={() => scrollToSection('contact')} className="hover:text-purple-400">
Contact
</button>
</div>
</div>
</nav>
);
}
```
## Troubleshooting
### Images Not Loading
Ensure images are in the `public` directory and referenced with absolute paths:
```typescript
<img src="/projects/myproject.png" alt="Project" />
```
### Typing Animation Not Working
Check that the component is marked as `'use client'` for client-side interactivity:
```typescript
'use client';
import { useState, useEffect } from 'react';
```
### Tailwind Styles Not Applied
Verify `tailwind.config.ts` content paths include all component directories:
```typescript
content: [
'./app/**/*.{js,ts,jsx,tsx,mdx}',
'./components/**/*.{js,ts,jsx,tsx,mdx}',
],
```
### Build Errors
Clear Next.js cache and rebuild:
```bash
rm -rf .next
npm run build
```
Scanned 9/8/2026
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!