Skip to main content
The Contact component provides a two-column layout with informational content and social links on one side, and a functional contact form on the other. Features smooth animations and theme-aware styling.

Overview

This component is built with Astro and creates an engaging contact section with a form, social media links, and descriptive text. All elements animate into view with different effects.

Source Location

~/workspace/source/src/components/contact.astro

Props

This component does not accept any props. All content is hardcoded within the component.

Usage

Basic Usage

---
import Contact from '../components/contact.astro';
---

<Contact />

Features

Two-Column Layout

  • Left column: Badge, title, description, and social links
  • Right column: Contact form with name, email, and message fields

Animations

Info Section (0.2s delay):
<ScrollAnimation className="contact-info" delay={0.2} client:load as="div">
Form Section (0.4s delay with slide-in):
<ScrollAnimation delay={0.4} variants={{
  hidden: { opacity: 0, x: 50 },
  visible: { opacity: 1, x: 0 }
}} client:load as="div">
Three social media links with SVG icons:
  1. Facebook - Full circle icon
  2. Instagram - Camera/square icon
  3. GitHub - Octocat icon
Each link includes aria-label for accessibility.

Layout Structure

contact-section
└── contact-inner (max-width: 1080px)
    ├── contact-info (ScrollAnimation wrapper)
    │   ├── contact-badge
    │   ├── contact-title
    │   ├── contact-description
    │   └── contact-socials
    │       ├── social-link (Facebook)
    │       ├── social-link (Instagram)
    │       └── social-link (GitHub)
    └── contact-form (ScrollAnimation wrapper)
        ├── form-group (name)
        │   ├── label
        │   └── input
        ├── form-group (email)
        │   ├── label
        │   └── input
        ├── form-group (message)
        │   ├── label
        │   └── textarea
        └── contact-submit (button)

Form Fields

Name Field

<div class="form-group">
  <label for="contact-name">Nombre</label>
  <input 
    type="text" 
    id="contact-name" 
    name="name" 
    placeholder="Tu nombre" 
    required 
  />
</div>

Email Field

<div class="form-group">
  <label for="contact-email">Correo electrónico</label>
  <input 
    type="email" 
    id="contact-email" 
    name="email" 
    placeholder="[email protected]" 
    required 
  />
</div>

Message Field

<div class="form-group">
  <label for="contact-message">Mensaje</label>
  <textarea 
    id="contact-message" 
    name="message" 
    rows="4" 
    placeholder="¿En qué podemos ayudarte?"
  ></textarea>
</div>

Submit Button

<button type="submit" class="contact-submit">
  Quiero ser parte
</button>

Responsive Behavior

Mobile (< 768px)

  • Single column stack
  • 2rem gap between sections
  • Form width: 100% (max-width: 480px)

Tablet+ (768px+)

  • Two columns: 1fr + 1fr
  • 5rem gap
  • Aligned to start (not center)
@media (min-width: 768px) {
  .contact-inner {
    grid-template-columns: 1fr 1fr;
    align-items: start;
    gap: 5rem;
  }
}

Styling Notes

Background Color

  • Light mode: Green dark (var(--color-green-dark))
  • Dark mode: Dark gray (#191919)
  • All text is white for contrast
Size: 2.5rem × 2.5rem
.social-link {
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 0.5rem;
  border: 1px solid rgba(255, 255, 255, 0.2);
  color: rgba(255, 255, 255, 0.7);
  transition: color 0.25s, border-color 0.25s, background 0.25s;
}

.social-link:hover {
  color: #ffffff;
  border-color: var(--color-orange);
  background: rgba(255, 255, 255, 0.05);
}

Form Input Styling

.form-group input,
.form-group textarea {
  width: 100%;
  padding: 0.75rem 1rem;
  border-radius: 0.5rem;
  border: 1px solid rgba(255, 255, 255, 0.15);
  background: rgba(255, 255, 255, 0.08);
  color: #ffffff;
  font-family: var(--font-sans);
  font-size: 0.9rem;
  outline: none;
  box-sizing: border-box;
}

.form-group input::placeholder,
.form-group textarea::placeholder {
  color: rgba(255, 255, 255, 0.35);
}

.form-group input:focus,
.form-group textarea:focus {
  border-color: var(--color-orange);
  background: rgba(255, 255, 255, 0.12);
}

Submit Button

.contact-submit {
  padding: 0.75rem 2rem;
  background: var(--color-orange);
  color: #ffffff;
  font-family: var(--font-pop);
  font-weight: 600;
  font-size: 0.9rem;
  border: none;
  border-radius: 0.5rem;
  cursor: pointer;
  transition: transform 0.25s, box-shadow 0.25s;
}

.contact-submit:hover {
  transform: translateY(-2px);
  box-shadow: 0 8px 24px rgba(185, 58, 5, 0.35);
}

Typography

  • Badge: --font-pop, 0.7rem, uppercase, orange border
  • Title: --font-montserrat, 700 weight, 1.75rem → 2.25rem (tablet+), white
  • Description: --font-sans, 1rem, white with 75% opacity
  • Labels: --font-pop, 0.8rem, 500 weight, white with 80% opacity

Form Configuration

Current form setup:
<form class="contact-form" action="#" method="POST">
Note: You’ll need to update the action attribute to point to your form handler endpoint.

Content Structure

Hardcoded Spanish content:
  • Badge: “Súmate” (Join us)
  • Title: “Esto lo construimos entre todos” (We build this together)
  • Description: Call to action for participation
  • Form labels: Spanish field names
  • Submit button: “Quiero ser parte” (I want to be part)

Section Spacing

padding: 5rem 2rem;        /* Mobile */
padding: 6rem 3rem;        /* Tablet (768px+) */
padding: 8rem 4rem;        /* Desktop (1024px+) */

Textarea Behavior

.form-group textarea {
  resize: vertical;
  min-height: 100px;
}
Users can resize vertically but not horizontally, with a minimum height of 100px.

Dependencies

  • ScrollAnimation.jsx - Animation wrapper component
  • Framer Motion (via ScrollAnimation)
  • CSS custom properties: --color-green-dark, --color-orange, --font-montserrat, --font-pop, --font-sans
  • SVG social icons (inline)

Customization Ideas

To make this component reusable:
interface SocialLink {
  platform: string;
  url: string;
  icon: string; // SVG path or component
}

interface Props {
  title?: string;
  description?: string;
  formAction: string;
  submitText?: string;
  socialLinks?: SocialLink[];
}

Form Handling

You’ll need to implement form handling. Options include:
  1. Server endpoint: Update action to your API route
  2. Form service: Use services like Formspree, Netlify Forms, etc.
  3. Client-side JavaScript: Add submit handler with fetch()
Example with JavaScript:
const form = document.querySelector('.contact-form');
form.addEventListener('submit', async (e) => {
  e.preventDefault();
  const formData = new FormData(form);
  // Handle submission
});

Accessibility

  • Proper label-input associations with for and id attributes
  • required attributes on name and email fields
  • aria-label on social links
  • Semantic HTML structure
  • High contrast white-on-dark design
  • Focus states on form inputs with orange border
  • Keyboard navigable elements

Build docs developers (and LLMs) love