📝 Form Elements Design Guide

Form elements є critical touchpoints між користувачами та системою. Whether collecting email для newsletter signup, dosage calculator inputs, або trip report submissions, well-designed forms reduce friction, prevent errors, та improve completion rates. Для mushroom education site, forms handle: cultivation log entries, safety checklists, species identification submissions, та user feedback. Effective form design balances visual clarity (labels, placeholders), validation feedback (error/success states), accessibility (keyboard navigation, screen readers), та mobile usability. Цей guide охоплює complete form element library з CSS, validation patterns, та best practices від WCAG 2.1 accessibility standards.

🎨 Form Elements Showcase

Contact Form Example

✓ Valid email address

💻 CSS Implementation

Base Input Styles:

/* Label */
.form-label {
  display: block;
  font-weight: 600;
  margin-bottom: 8px;
  color: #2c3e50;
  font-size: 0.95em;
}

/* Required indicator */
.form-label::after {
  content: " *";
  color: #dc3545;
}

/* Text Input */
.form-input {
  width: 100%;
  padding: 12px 16px;
  font-size: 1em;
  line-height: 1.5;
  color: #2c3e50;
  background: white;
  border: 2px solid #e9ecef;
  border-radius: 8px;
  transition: all 0.3s ease;
  font-family: inherit;
}

/* Focus State */
.form-input:focus {
  outline: none;
  border-color: #f857a6;
  box-shadow: 0 0 0 3px rgba(248, 87, 166, 0.1);
}

/* Hover State */
.form-input:hover {
  border-color: #dee2e6;
}

/* Disabled State */
.form-input:disabled {
  background: #f8f9fa;
  cursor: not-allowed;
  opacity: 0.6;
}

/* Placeholder */
.form-input::placeholder {
  color: #adb5bd;
  opacity: 1;
}

Validation States:

/* Error State */
.form-input.error {
  border-color: #dc3545;
  background: #fff5f5;
}

.form-input.error:focus {
  box-shadow: 0 0 0 3px rgba(220, 53, 69, 0.1);
}

/* Success State */
.form-input.success {
  border-color: #28a745;
  background: #f0fff4;
}

.form-input.success:focus {
  box-shadow: 0 0 0 3px rgba(40, 167, 69, 0.1);
}

/* Validation Messages */
.form-message {
  margin-top: 6px;
  font-size: 0.875em;
  display: flex;
  align-items: center;
  gap: 6px;
}

.form-message.error {
  color: #dc3545;
}

.form-message.error::before {
  content: "⚠️";
}

.form-message.success {
  color: #28a745;
}

.form-message.success::before {
  content: "✓";
}

Select Dropdown:

.form-select {
  width: 100%;
  padding: 12px 16px;
  padding-right: 40px; /* Space для arrow */
  font-size: 1em;
  border: 2px solid #e9ecef;
  border-radius: 8px;
  background: white;
  cursor: pointer;
  font-family: inherit;
  
  /* Remove default arrow */
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  
  /* Custom arrow */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8'%3E%3Cpath fill='%232c3e50' d='M6 8L0 0h12z'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 16px center;
}

.form-select:focus {
  outline: none;
  border-color: #f857a6;
  box-shadow: 0 0 0 3px rgba(248, 87, 166, 0.1);
}

Checkboxes та Radio Buttons:

/* Modern approach: use accent-color */
.form-checkbox,
.form-radio {
  width: 20px;
  height: 20px;
  cursor: pointer;
  accent-color: #f857a6; /* Modern browsers */
}

/* Wrapper для label clickability */
.checkbox-wrapper,
.radio-wrapper {
  display: flex;
  align-items: center;
  gap: 10px;
  cursor: pointer;
}

.checkbox-wrapper:hover,
.radio-wrapper:hover {
  opacity: 0.8;
}

/* Custom checkbox (advanced) */
.custom-checkbox {
  position: relative;
  width: 20px;
  height: 20px;
}

.custom-checkbox input {
  opacity: 0;
  position: absolute;
}

.custom-checkbox-box {
  width: 20px;
  height: 20px;
  border: 2px solid #e9ecef;
  border-radius: 4px;
  background: white;
  transition: all 0.3s;
}

.custom-checkbox input:checked + .custom-checkbox-box {
  background: #f857a6;
  border-color: #f857a6;
}

.custom-checkbox input:checked + .custom-checkbox-box::after {
  content: "✓";
  color: white;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

File Upload:

<!-- HTML -->
<label class="file-upload">
  <input type="file" accept="image/*" />
  <div>📁 Click to upload або drag and drop</div>
  <div class="file-hint">PNG, JPG up to 10MB</div>
</label>

/* CSS */
.file-upload {
  border: 2px dashed #e9ecef;
  border-radius: 8px;
  padding: 30px;
  text-align: center;
  cursor: pointer;
  transition: all 0.3s;
}

.file-upload:hover {
  border-color: #f857a6;
  background: #fff7fa;
}

.file-upload input[type="file"] {
  display: none; /* Hide default input */
}

.file-hint {
  font-size: 0.875em;
  color: #6c757d;
  margin-top: 8px;
}

♿ Accessibility

Proper Label Association:

<!-- Method 1: for/id association -->
<label for="email" class="form-label">Email</label>
<input type="email" id="email" class="form-input" />

<!-- Method 2: wrap input -->
<label class="form-label">
  Email
  <input type="email" class="form-input" />
</label>

ARIA Attributes:

<!-- Required field -->
<input type="text" aria-required="true" required />

<!-- Error state -->
<input type="email" 
  class="form-input error"
  aria-invalid="true" 
  aria-describedby="email-error" />
<div id="email-error" class="form-message error">
  Invalid email format
</div>

<!-- Helper text -->
<input type="password" 
  aria-describedby="password-hint" />
<div id="password-hint" class="form-hint">
  Must be at least 8 characters
</div>

✅ Form Elements Checklist

Implementation Checklist:

  • ☐ All inputs have associated labels (for/id або wrapper)
  • ☐ Focus states clearly visible (outline або box-shadow)
  • ☐ Placeholder text не замінює labels
  • ☐ Validation states: error та success styled
  • ☐ Error messages descriptive та specific
  • ☐ Required fields marked (*)
  • ☐ Touch targets ≥ 44x44px на mobile
  • ☐ ARIA attributes: aria-required, aria-invalid, aria-describedby
  • ☐ Keyboard navigation works (Tab, Shift+Tab)
  • ☐ Color contrast meets WCAG AA (4.5:1)
  • ☐ Disabled states clearly indicated
  • ☐ File upload shows selected filename