Contact

Contact form patterns with split layouts, contact information sidebars, and map integration. Accessible and responsive designs for customer communication.

Overview

Contact forms are essential for user communication. These patterns demonstrate various layouts from simple centered forms to complex split designs with contact information and map placeholders.

Key features:

  • <form-field> for consistent input styling and validation
  • <textarea> with appropriate rows attribute for message input
  • <layout-sidebar> for split layouts with contact information
  • <icon-wc> for visual contact method indicators
  • Proper autocomplete attributes for form autofill
  • Accessible validation with <output> and aria-live

Simple Contact Form

A centered contact form using data-layout="cover" for vertical centering. Includes name, email, and message fields with validation support.

<body data-layout="cover" data-layout-min="100vh" data-layout-padding="l"> <layout-card data-layout-max="narrow" data-padding="l" data-layout-principal> <form action="/contact" method="POST" data-layout="stack" data-layout-gap="l"> <header data-layout="stack" data-layout-gap="s"> <h1>Get in touch</h1> <p>We'd love to hear from you. Send us a message and we'll respond as soon as possible.</p> </header> <form-field> <label for="name">Name</label> <input type="text" id="name" name="name" required autocomplete="name" placeholder="Your name" aria-describedby="name-error"/> <output id="name-error" class="error" for="name" aria-live="polite"> Please enter your name. </output> </form-field> <form-field> <label for="email">Email</label> <input type="email" id="email" name="email" required autocomplete="email" placeholder="you@example.com" aria-describedby="email-error"/> <output id="email-error" class="error" for="email" aria-live="polite"> Please enter a valid email address. </output> </form-field> <form-field> <label for="message">Message</label> <textarea id="message" name="message" rows="5" required placeholder="How can we help you?" aria-describedby="message-error"></textarea> <output id="message-error" class="error" for="message" aria-live="polite"> Please enter a message. </output> </form-field> <button type="submit">Send message</button> </form> </layout-card> </body>

Split Layout with Contact Info

A two-column layout using <layout-sidebar> with the form as the main content and contact information in the sidebar. Includes address, phone, email, and business hours.

<section class="contact-section"> <layout-cover data-layout-min="100vh" data-layout-padding="xl"> <layout-center data-layout-max="wide"> <layout-sidebar data-layout-gap="2xl" data-layout-sidebar-width="narrow" data-layout-content-min="50"> <!-- Form Panel --> <section class="form-card"> <form action="/contact" method="POST" data-layout="stack" data-layout-gap="l"> <header data-layout="stack" data-layout-gap="s"> <h1>Send us a message</h1> <p>Fill out the form and our team will get back to you within 24 hours.</p> </header> <form-field> <label for="name">Name</label> <input type="text" id="name" name="name" required autocomplete="name" placeholder="Your name"/> </form-field> <form-field> <label for="email">Email</label> <input type="email" id="email" name="email" required autocomplete="email" placeholder="you@example.com"/> </form-field> <form-field> <label for="subject">Subject</label> <input type="text" id="subject" name="subject" required placeholder="What is this regarding?"/> </form-field> <form-field> <label for="message">Message</label> <textarea id="message" name="message" rows="5" required placeholder="Tell us more about your inquiry..."></textarea> </form-field> <button type="submit">Send message</button> </form> </section> <!-- Contact Info Sidebar --> <aside class="contact-info" data-layout="stack" data-layout-gap="xl"> <div data-layout="stack" data-layout-gap="m"> <h3>Contact information</h3> <p>Reach out to us through any of these channels.</p> </div> <div data-layout="stack" data-layout-gap="l"> <div data-layout="cluster" data-layout-gap="m" data-layout-align="start"> <icon-wc name="map-pin"></icon-wc> <div data-layout="stack" data-layout-gap="xs"> <span class="contact-item-label">Address</span> <span class="contact-item-value"> 123 Business Ave, Suite 100<br/> San Francisco, CA 94102 </span> </div> </div> <div data-layout="cluster" data-layout-gap="m" data-layout-align="start"> <icon-wc name="phone"></icon-wc> <div data-layout="stack" data-layout-gap="xs"> <span class="contact-item-label">Phone</span> <span class="contact-item-value"> <a href="tel:+14155551234">(415) 555-1234</a> </span> </div> </div> <div data-layout="cluster" data-layout-gap="m" data-layout-align="start"> <icon-wc name="mail"></icon-wc> <div data-layout="stack" data-layout-gap="xs"> <span class="contact-item-label">Email</span> <span class="contact-item-value"> <a href="mailto:hello@example.com">hello@example.com</a> </span> </div> </div> </div> <div data-layout="stack" data-layout-gap="m"> <h3>Business hours</h3> <div class="hours-list" data-layout="stack" data-layout-gap="xs"> <div data-layout="cluster" data-layout-justify="between"> <span>Monday - Friday</span> <span>9:00 AM - 6:00 PM</span> </div> <div data-layout="cluster" data-layout-justify="between"> <span>Saturday</span> <span>10:00 AM - 4:00 PM</span> </div> <div data-layout="cluster" data-layout-justify="between"> <span>Sunday</span> <span>Closed</span> </div> </div> </div> </aside> </layout-sidebar> </layout-center> </layout-cover> </section>

Contact Info Styles

.contact-section { background: var(--color-surface-raised); } .form-card { background: var(--color-surface); border-radius: var(--radius-l); box-shadow: 0 1px 3px oklch(0% 0 0 / 0.1); padding: var(--size-l); } .contact-info h3 { font-size: var(--font-size-lg); margin: 0; } .contact-info icon-wc { color: var(--color-interactive); flex-shrink: 0; margin-top: var(--size-xs); } .contact-item-label { font-weight: var(--font-weight-medium); } .contact-item-value { color: var(--color-text-muted); font-size: var(--font-size-sm); } .hours-list { font-size: var(--font-size-sm); color: var(--color-text-muted); }

With Map

Contact form with a <geo-map> component for displaying your location. Uses a centered header above a split layout with free OpenStreetMap tiles.

<section class="contact-section"> <layout-cover data-layout-min="100vh" data-layout-padding="xl"> <layout-center data-layout-max="wide" data-layout-gap="2xl"> <!-- Header --> <header class="contact-header" data-layout="stack" data-layout-gap="s"> <h1>Contact us</h1> <p>Have questions? We're here to help. Send us a message or visit our office.</p> </header> <!-- Content Grid --> <layout-sidebar data-layout-gap="xl" data-layout-sidebar-width="wide" data-layout-content-min="45"> <!-- Contact Form --> <section class="form-card"> <form action="/contact" method="POST" data-layout="stack" data-layout-gap="l"> <h2>Send a message</h2> <div data-layout="split" data-layout-gap="m"> <form-field> <label for="first-name">First name</label> <input type="text" id="first-name" name="first_name" required autocomplete="given-name" placeholder="John"/> </form-field> <form-field> <label for="last-name">Last name</label> <input type="text" id="last-name" name="last_name" required autocomplete="family-name" placeholder="Doe"/> </form-field> </div> <form-field> <label for="email">Email</label> <input type="email" id="email" name="email" required autocomplete="email" placeholder="john@example.com"/> </form-field> <form-field> <label for="phone">Phone (optional)</label> <input type="tel" id="phone" name="phone" autocomplete="tel" placeholder="(555) 123-4567"/> </form-field> <form-field> <label for="message">Message</label> <textarea id="message" name="message" rows="4" required placeholder="How can we help you?"></textarea> </form-field> <button type="submit">Send message</button> </form> </section> <!-- Map Sidebar --> <aside> <geo-map lat="37.7749" lng="-122.4194" zoom="14" style="--geo-map-height: 100%; min-height: 400px;"> <address> 123 Business Ave, Suite 100<br/> San Francisco, CA 94102 </address> </geo-map> </aside> </layout-sidebar> </layout-center> </layout-cover> </section>

Map Styles

.form-card { background: var(--color-surface); border-radius: var(--radius-l); box-shadow: 0 1px 3px oklch(0% 0 0 / 0.1); padding: var(--size-l); } aside geo-map { --geo-map-height: 100%; min-height: 400px; }

Configuration

Key configuration options for contact forms:

Element/Attribute Purpose Options
textarea rows Message field height 4, 5, 6 (adjust to content needs)
layout-sidebar data-sidebar-width Contact info sidebar width narrow, default, wide
layout-sidebar data-content-min Minimum form width before wrapping 45, 50, 60 (percentage)
data-layout="split" Side-by-side form fields Use for first/last name pairs
autocomplete Enable browser autofill name, email, tel, given-name, family-name

Usage Notes

  • Required fields: Mark essential fields with required attribute; <form-field> adds visual asterisk automatically
  • Validation messages: Use <output class="error"> with aria-describedby linking to the input
  • Success states: Consider showing a success message or redirecting after submission
  • Spam prevention: Add honeypot fields or CAPTCHA for production forms
  • Map integration: The <geo-map> component uses free OpenStreetMap tiles — no API key needed
  • Phone links: Use tel: protocol for clickable phone numbers on mobile
  • Email links: Use mailto: protocol for email addresses
  • Accessibility: All form fields have labels, icons have appropriate aria attributes

Related

Sign In

Login form patterns with validation

Form Field

Form field element with validation

Layout Sidebar

Sidebar layout for split designs

Icon

Icon component for contact indicators

Geo Map

Map component for location display