This is the third and final part of my first React project for the Frontend Mentor's Digital Bank Landing Page Challenge. I'm excited to say that I finally finished it.
Live Demo: https://bank-landing-page-react-gmtz.vercel.app/
Github Repo: https://github.com/ayra-baet/bank-landing-page-react
Learning Component Reusability Beyond Small Elements
At first, I thought this final part would mostly involve finishing the Articles and Footer. But while building, I realized something more important:
React's reusability isn't limited to small UI elements like buttons or cards; entire sections can be reusable too.
Earlier in this project, I reused a single Button component across the header, hero, and footer. This time, I noticed that the Features and Articles sections shared almost the same structure:
- both had an h2 heading
- both used a grid layout
- both wrapped child components
The only real difference was that the Features section included a description paragraph.
That immediately felt like a perfect use case for a reusable component with conditional rendering.
So I created a reusable Section component:
function Section({ backgroundColor, title, description, children }) {
return(
<section
className={backgroundColor}
aria-labelledby={`${title}-heading`}
>
<div className="container section__container">
<div className="section__header">
<h2 id={`${title}-heading`}>{title}</h2>
{description && <p>{description}</p>}
</div>
<div className="section__grid">
{children}
</div>
</div>
</section>
);
}
Then I reused it inside my LandingPage component:
function LandingPage() {
return(
<>
{/* other LandingPage JSX */}
<section id="features">
<Section
backgroundColor="section--gray-100"
title="Why choose Digitalbank?"
description="We leverage Open Banking to turn your bank account into your financial hub. Control your finances like never before."
>
<Features />
</Section>
</section>
<section id="articles">
<Section
backgroundColor="section--gray-50"
title="Latest Articles"
>
<Articles />
</Section>
</section>
{/* other LandingPage JSX */}
</>
);
}
This made the code feel much cleaner and more scalable. If I ever add another section with the same structure, I can simply reuse the component instead of rewriting markup from scratch.
That was one of the biggest "React mindset" moments during the project.
Adding Animations with CSS + React Hooks
For the Hero Section, I wanted a fade-in + slide-up animation when the mockup image loads.
In plain HTML/CSS, I'd rely on CSS animations triggered by page load. But in React, I used the useState hook with the onLoad event:
function HeroSection() {
const [imageLoaded, setImageLoaded] = useState(false);
return(
<section
className={`hero ${imageLoaded ? "loaded" : ""}`}
aria-labelledby="hero-title"
>
{/* other hero JSX */}
<img
src={mockup}
alt="Mockup of a banking app on mobile phones"
className="hero__mockup"
onLoad={() => setImageLoaded(true)}
/>
{/* other hero JSX */}
</section>
);
}
Here's how it works:
- imageLoaded starts as false
- Once the image finishes loading, setImageLoaded(true) runs
- React adds the loaded class
- The CSS animation then triggers
This ensures the animation plays only after the image is fully ready, creating a smoother experience.
Staggered Animations with Framer Motion
The last animation I added was a staggered reveal for the article cards.
Instead of writing complex JavaScript with the Intersection Observer API, I used Framer Motion, which is declarative and integrates beautifully with React.
I defined variants for the parent container and child cards:
// Section component
const containerVariants = {
hidden: {},
visible: {
transition: shouldReduceMotion
? {}
: {
staggerChildren: 0.12
}
}
};
// Articles component
const cardVariants = {
hidden: {
opacity: shouldReduceMotion ? 1 : 0,
y: shouldReduceMotion ? 0: 30
},
visible: {
opacity: 1,
y: 0,
transition: shouldReduceMotion
? { duration: 0 }
: {
duration: 0.5,
ease: "easeOut"
}
}
};
Then applied them:
// Section component
<motion.div
variants={containerVariants}
initial={shouldReduceMotion ? false : "hidden"}
whileInView={shouldReduceMotion ? undefined : "visible"}
viewport={{ once: true, amount: 0.2 }}
className="section__grid"
>
{children}
</motion.div>
// Articles component
<motion.article
variants={cardVariants}
className="article__card"
key={article.id}
>
{/* article content */}
</motion.article>
The result is a smooth, staggered animation in which each card slides upward one after another.
What I liked most was how simple Framer Motion made everything. The whileInView prop automatically handles scroll-triggered animations without needing to manually wire up observers.
Key Lessons Learned
1. Component Architecture
Breaking the UI into reusable pieces made the project much easier to manage.
Each component owns its own markup and logic, while the LandingPage component simply arranges sections together.
That separation made the codebase feel more organized and scalable.
2. React Hooks
Hooks became essential throughout this project.
I used:
- useState for menu toggles and image load tracking
- useEffect for disabling page scroll when the mobile menu is open
Before this project, hooks felt abstract while reading documentation. Building something real made them finally "click" for me.
3. Props and State Management
Passing props down and lifting state up are core React patterns that I practiced repeatedly here.
The more I used them, the more I understood how React components communicate and stay flexible.
4. CSS Was Harder Than React
Ironically, CSS ended up being the hardest part of the project.
I spent far more time dealing with:
- layouts
- spacing
- positioning
- responsiveness
- overflow issues
than writing actual React logic.
Using functions like clamp() across breakpoints helped improve my responsive design skills a lot.
5. Accessibility Matters
I also tried to make the project more accessible by:
- adding aria-labelledby
- respecting prefers-reduced-motion
- using Framer Motion's useReducedMotion hook
This reminded me that accessibility shouldn't be treated as an afterthought.
Final Thoughts
This project tested both my CSS fundamentals and React basics.
Even though it wasn't the most React-heavy application, it gave me hands-on experience with:
- component architecture
- hooks
- reusable layouts
- Framer Motion
- accessibility considerations
More importantly, it taught me persistence.
I got stuck multiple times. I rewrote code, researched solutions, broke layouts, and made mistakes, but I kept going until everything finally came together.
And honestly, that might be the biggest lesson from this entire project.
I now feel much more confident building future React applications, and I can already see how much more structured my approach has become compared to when I started.
On to the next project!
Top comments (1)
What I find interesting is that your “React mindset” moment wasn’t really about React.
It was about abstraction.
First you reuse buttons.
Then you reuse cards.
Then you reuse sections.
Eventually you start seeing patterns, boundaries, and responsibilities everywhere.
That’s one of the biggest shifts in software engineering: moving from writing code to identifying reusable concepts.
The framework changes. That way of thinking tends to stay with you.