Welcome to Vanilla Breeze
This bell pulls live notifications from /go/notify/messages — the same contract documented at /docs/concepts/service-contracts/. Static articles like this one are the no-JS / no-backend fallback.
This bell pulls live notifications from /go/notify/messages — the same contract documented at /docs/concepts/service-contracts/. Static articles like this one are the no-JS / no-backend fallback.
Contact form patterns with split layouts, contact information sidebars, and map integration. Accessible and responsive designs for customer communication.
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 indicatorsautocomplete attributes for form autofill<output> and aria-liveA 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="[email protected]" 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>
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="[email protected]"/> </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:[email protected]">[email protected]</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-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);}
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="[email protected]"/> </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>
.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;}
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 |
required attribute; <form-field> adds visual asterisk automatically<output class="error"> with aria-describedby linking to the input<geo-map> component uses free OpenStreetMap tiles — no API key neededtel: protocol for clickable phone numbers on mobilemailto: protocol for email addressesLogin form patterns with validation
Form field element with validation
Sidebar layout for split designs
Icon component for contact indicators
Map component for location display