Skip to main content

Overview

The ContactSection component serves as the final section of the portfolio, providing contact information, social links, and footer details. It features centered content with call-to-action buttons and copyright information.

Features

  • Centered call-to-action layout
  • Social media and contact links
  • Icon integration from Lucide React
  • Responsive button layout
  • Footer with divider
  • Copyright and tagline
  • External link handling

Component Structure

import { motion } from "framer-motion";
import { Linkedin, Globe, Mail } from "lucide-react";

const ContactSection = () => {
  return (
    <section id="contact" className="py-24 md:py-32">
      <div className="container px-6">
        <div className="max-w-3xl mx-auto text-center">
          {/* Header and CTA buttons */}
        </div>
      </div>

      {/* Footer */}
      <div className="container px-6 mt-24">
        {/* Footer content */}
      </div>
    </section>
  );
};

Section Header

<motion.div
  initial={{ opacity: 0, y: 30 }}
  whileInView={{ opacity: 1, y: 0 }}
  viewport={{ once: true }}
  transition={{ duration: 0.6 }}
>
  <p className="text-primary font-heading text-sm tracking-[0.2em] uppercase mb-3">
    Contacto
  </p>
  <h2 className="font-heading text-3xl md:text-5xl font-bold mb-6">
    Hablemos
  </h2>
  <p className="text-muted-foreground text-lg leading-relaxed mb-12">
    ¿Buscas un partner tecnológico que entienda tu negocio? 
    Conectemos y exploremos cómo la tecnología puede impulsar tu empresa.
  </p>
</motion.div>
Three primary contact methods are provided:
<a
  href="https://www.linkedin.com/in/carrascosa"
  target="_blank"
  rel="noopener noreferrer"
  className="inline-flex items-center gap-3 px-6 py-3 rounded-lg 
             bg-primary text-primary-foreground font-heading font-medium 
             hover:opacity-90 transition-opacity"
>
  <Linkedin className="w-5 h-5" />
  LinkedIn
</a>
Primary CTA with filled background

Button Variants

Primary Button (LinkedIn)

className="inline-flex items-center gap-3 px-6 py-3 rounded-lg 
          bg-primary text-primary-foreground font-heading font-medium 
          hover:opacity-90 transition-opacity"
  • Filled background with primary color
  • White text on colored background
  • Opacity hover effect (90%)

Secondary Buttons (Website, Email)

className="inline-flex items-center gap-3 px-6 py-3 rounded-lg 
          border border-border text-foreground font-heading font-medium 
          hover:border-primary/50 transition-colors"
  • Outline style with border
  • Default text color
  • Border color transition on hover

Button Layout

<motion.div
  initial={{ opacity: 0, y: 20 }}
  whileInView={{ opacity: 1, y: 0 }}
  viewport={{ once: true }}
  transition={{ delay: 0.2, duration: 0.6 }}
  className="flex flex-col sm:flex-row items-center justify-center gap-4"
>
  {/* Buttons */}
</motion.div>
Vertical stack - flex-col
<div className="container px-6 mt-24">
  <div className="section-divider mb-8" />
  <div className="flex flex-col md:flex-row items-center justify-between 
                  text-muted-foreground/50 text-sm">
    <p className="font-heading">© 2026 David Carrascosa Bolaños</p>
    <p>CTO · Grupo SADE · Beyond Technology</p>
  </div>
</div>
1

Divider

The section-divider class creates a horizontal line separator
2

Copyright

Left-aligned on desktop, centered on mobile
3

Tagline

Right-aligned on desktop, below copyright on mobile

Divider Styling

Add this to your global CSS:
.section-divider {
  width: 100%;
  height: 1px;
  background: linear-gradient(90deg, 
    transparent, 
    hsl(var(--border)) 50%, 
    transparent);
}
All external links include security attributes:
target="_blank"           // Opens in new tab
rel="noopener noreferrer" // Security best practice
Always use rel="noopener noreferrer" with target="_blank" to prevent security vulnerabilities and performance issues.

Animation Details

ElementDelayDurationEffect
Header0s0.6sFade in, slide up
Buttons0.2s0.6sFade in, slide up

Full Component Code

import { motion } from "framer-motion";
import { Linkedin, Globe, Mail } from "lucide-react";

const ContactSection = () => {
  return (
    <section id="contact" className="py-24 md:py-32">
      <div className="container px-6">
        <div className="max-w-3xl mx-auto text-center">
          <motion.div
            initial={{ opacity: 0, y: 30 }}
            whileInView={{ opacity: 1, y: 0 }}
            viewport={{ once: true }}
            transition={{ duration: 0.6 }}
          >
            <p className="text-primary font-heading text-sm tracking-[0.2em] uppercase mb-3">
              Contacto
            </p>
            <h2 className="font-heading text-3xl md:text-5xl font-bold mb-6">
              Hablemos
            </h2>
            <p className="text-muted-foreground text-lg leading-relaxed mb-12">
              ¿Buscas un partner tecnológico que entienda tu negocio? 
              Conectemos y exploremos cómo la tecnología puede impulsar tu empresa.
            </p>
          </motion.div>

          <motion.div
            initial={{ opacity: 0, y: 20 }}
            whileInView={{ opacity: 1, y: 0 }}
            viewport={{ once: true }}
            transition={{ delay: 0.2, duration: 0.6 }}
            className="flex flex-col sm:flex-row items-center justify-center gap-4"
          >
            <a
              href="https://www.linkedin.com/in/carrascosa"
              target="_blank"
              rel="noopener noreferrer"
              className="inline-flex items-center gap-3 px-6 py-3 rounded-lg bg-primary text-primary-foreground font-heading font-medium hover:opacity-90 transition-opacity"
            >
              <Linkedin className="w-5 h-5" />
              LinkedIn
            </a>
            <a
              href="https://www.grupo-sade.com"
              target="_blank"
              rel="noopener noreferrer"
              className="inline-flex items-center gap-3 px-6 py-3 rounded-lg border border-border text-foreground font-heading font-medium hover:border-primary/50 transition-colors"
            >
              <Globe className="w-5 h-5" />
              Grupo SADE
            </a>
            <a
              href="mailto:[email protected]"
              className="inline-flex items-center gap-3 px-6 py-3 rounded-lg border border-border text-foreground font-heading font-medium hover:border-primary/50 transition-colors"
            >
              <Mail className="w-5 h-5" />
              Email
            </a>
          </motion.div>
        </div>
      </div>

      {/* Footer */}
      <div className="container px-6 mt-24">
        <div className="section-divider mb-8" />
        <div className="flex flex-col md:flex-row items-center justify-between text-muted-foreground/50 text-sm">
          <p className="font-heading">© 2026 David Carrascosa Bolaños</p>
          <p>CTO · Grupo SADE · Beyond Technology</p>
        </div>
      </div>
    </section>
  );
};

export default ContactSection;

Customization

1

Update Links

Replace LinkedIn, website, and email URLs with your own
2

Add Social Links

Import additional icons (Twitter, GitHub) and add more buttons
3

Change Button Styles

Modify primary/secondary button classes for different visual hierarchy
4

Update Footer

Replace copyright and tagline text with your information

Adding More Contact Options

import { Github, Twitter } from "lucide-react";

// Add to button container
<a href="https://github.com/username" /* ... */>
  <Github className="w-5 h-5" />
  GitHub
</a>

Usage Example

import ContactSection from '@/components/ContactSection';

function App() {
  return (
    <>
      <ExperienceSection />
      <ContactSection />
    </>
  );
}

Accessibility

Best practices implemented:
  • Descriptive link text (not “Click here”)
  • External link indicators (target="_blank")
  • Security attributes (rel="noopener noreferrer")
  • Semantic HTML structure

Build docs developers (and LLMs) love