Goal

Create Contact: a centered, accessible form with name, email, and message fields that look clear in light and dark mode.

Contact.jsx

function Contact() {
  return (
    <section id="contact" className="bg-white py-20 dark:bg-slate-900">
      <div className="mx-auto flex max-w-5xl flex-col items-center px-6">
        <h2 className="mb-2 text-center text-3xl font-bold text-slate-900 dark:text-slate-100">
          Contact
        </h2>
        <p className="mb-10 max-w-2xl text-center text-slate-600 dark:text-slate-400">
          Have a project or question? Send a message: I usually reply within a
          few days.
        </p>

        <form
          className="mx-auto grid w-full max-w-2xl gap-4"
          onSubmit={(event) => {
            event.preventDefault();
            alert("Thanks! Wire this form to an API or email service later.");
          }}
        >
          <label className="grid gap-1 text-sm font-medium text-slate-700 dark:text-slate-200">
            Name
            <input
              type="text"
              required
              className="w-full rounded-md border border-slate-300 bg-white px-3 py-2 text-slate-900 shadow-sm outline-none transition focus:border-blue-500 focus:ring-2 focus:ring-blue-200 dark:border-slate-600 dark:bg-slate-900 dark:text-slate-100"
            />
          </label>

          <label className="grid gap-1 text-sm font-medium text-slate-700 dark:text-slate-200">
            Email
            <input
              type="email"
              required
              className="w-full rounded-md border border-slate-300 bg-white px-3 py-2 text-slate-900 shadow-sm outline-none transition focus:border-blue-500 focus:ring-2 focus:ring-blue-200 dark:border-slate-600 dark:bg-slate-900 dark:text-slate-100"
            />
          </label>

          <label className="grid gap-1 text-sm font-medium text-slate-700 dark:text-slate-200">
            Message
            <textarea
              rows={5}
              required
              className="w-full rounded-md border border-slate-300 bg-white px-3 py-2 text-slate-900 shadow-sm outline-none transition focus:border-blue-500 focus:ring-2 focus:ring-blue-200 dark:border-slate-600 dark:bg-slate-900 dark:text-slate-100"
            />
          </label>

          <button
            type="submit"
            className="w-full rounded-md bg-blue-600 px-5 py-3 text-sm font-semibold text-white transition hover:bg-blue-700 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-500 active:scale-95"
          >
            Send message
          </button>
        </form>
      </div>
    </section>
  );
}

export default Contact;

The alert is a stand-in. Later you can post to Formspree, Netlify Forms, or your own API.

Tailwind chunks explained: centered section

Class Meaning
flex flex-col items-center Center heading, blurb, and form as a column
text-center Center the heading and intro text
max-w-2xl Comfortable reading / form width
w-full Form still fills that max width on phones

Tailwind chunks explained: form layout

Class Meaning
grid gap-4 Stack fields with even spacing
grid gap-1 on <label> Small gap between label text and input
text-sm font-medium Clear field labels
wrapping control in <label> Clicking the label focuses the input

Tailwind chunks explained: inputs

Class Meaning
w-full Full width of the form
rounded-md border Soft outlined field
border-slate-300 / dark:border-slate-600 Theme-aware border
bg-white / dark:bg-slate-900 Field background
px-3 py-2 Typing space inside the control
shadow-sm Slight depth
outline-none Remove default focus outline (we replace it)
transition Smooth focus style change
focus:border-blue-500 Blue border when focused
focus:ring-2 focus:ring-blue-200 Soft focus ring for visibility

Tailwind chunks explained: submit button states

Class Meaning
w-full Full-width primary action
bg-blue-600 / hover:bg-blue-700 Default + hover fill
transition Animate hover and active
focus-visible:outline Keyboard-only focus ring (mouse clicks stay clean)
focus-visible:outline-2 Ring thickness
focus-visible:outline-offset-2 Gap between button and ring
focus-visible:outline-blue-500 Ring color
active:scale-95 Slight press-in on click

Wire into App.jsx

import Navbar from "./components/Navbar";
import Hero from "./components/Hero";
import Skills from "./components/Skills";
import Projects from "./components/Projects";
import Contact from "./components/Contact";

function App() {
  return (
    <div className="min-h-screen bg-surface font-sans text-ink antialiased dark:bg-slate-950 dark:text-slate-100">
      <Navbar />

      <main>
        <Hero />
        <Skills />
        <Projects />
        <Contact />
      </main>
    </div>
  );
}

export default App;

Check

  • Tab through fields: focus rings are obvious
  • Required validation blocks empty submits
  • Dark mode keeps inputs and labels readable
  • Nav Contact and Hero Get in touch both land here

Next: add Footer and finish the page.