Files
html-over-js/index.html

1221 lines
37 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<title>The Complete Native HTML Dominance Guide</title>
<style>
:root {
--color-bg: #ffffff;
--color-card: #f8f9fa;
--color-primary: #0066cc;
--color-primary-hover: #0052a3;
--color-danger: #dc3545;
--color-warning: #856404;
--color-warning-bg: #fff3cd;
--color-content-bg: #f1f3f4;
--color-border: #dee2e6;
--color-text: #212529;
--color-text-muted: #6c757d;
--color-code-bg: #f8f9fa;
--color-code-text: #0066cc;
--shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
--radius: 8px;
--focus-outline: 2px solid #0066cc;
--focus-outline-danger: 2px solid #dc3545;
--focus-offset: 2px;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
line-height: 1.6;
max-width: 1200px;
margin: 0 auto;
padding: 2rem;
background: var(--color-bg);
color: var(--color-text);
min-height: 100vh;
}
.hero {
text-align: center;
margin-bottom: 4rem;
padding: 3rem;
background: var(--color-card);
border-radius: var(--radius);
box-shadow: var(--shadow);
border: 1px solid var(--color-border);
}
.hero:focus-within {
outline: var(--focus-outline);
outline-offset: var(--focus-offset);
}
.hero h1 {
font-size: clamp(2rem, 5vw, 3.5rem);
margin-bottom: 1.5rem;
color: var(--color-primary);
font-weight: 700;
letter-spacing: -0.02em;
}
.hero .subtitle {
font-size: 1.125rem;
color: var(--color-text-muted);
max-width: 700px;
margin: 0 auto;
line-height: 1.5;
}
.comparison-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 2rem;
margin: 2rem 0;
}
.section {
margin: 4rem 0;
}
.section-title {
font-size: 2rem;
margin-bottom: 2rem;
padding: 1.5rem 0;
text-align: center;
color: var(--color-primary);
position: relative;
font-weight: 600;
}
.section-title::after {
content: '';
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 60px;
height: 2px;
background: var(--color-primary);
}
.column {
background: var(--color-card);
padding: 2rem;
border-radius: var(--radius);
box-shadow: var(--shadow);
border: 1px solid var(--color-border);
transition: box-shadow 0.2s ease;
position: relative;
}
.column:hover {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
.column:focus-within {
outline: var(--focus-outline);
outline-offset: var(--focus-offset);
}
.column.bad:focus-within {
outline: var(--focus-outline-danger);
}
.column h3 {
color: var(--color-text);
border-bottom: 1px solid var(--color-border);
padding-bottom: 1rem;
margin-bottom: 2rem;
font-size: 1.25rem;
font-weight: 600;
}
.bad {
border-left: 3px solid var(--color-danger);
}
.bad h3::before {
content: '⚠️ ';
}
.good {
border-left: 3px solid var(--color-primary);
}
.good h3::before {
content: '✅ ';
}
.accessibility-note {
background: var(--color-warning-bg);
border: 1px solid #ffc107;
color: var(--color-warning);
padding: 1rem;
border-radius: var(--radius);
margin: 1.5rem 0;
font-size: 0.875rem;
}
.code-block {
/*display: none;*/
background: var(--color-code-bg);
color: var(--color-code-text);
padding: 2rem 1.5rem 1rem;
border-radius: var(--radius);
overflow-x: auto;
font-family: 'SF Mono', Monaco, 'Cascadia Code', monospace;
font-size: 0.875rem;
margin: 1.5rem 0;
border: 1px solid var(--color-border);
position: relative;
}
.code-block:focus {
outline: var(--focus-outline);
outline-offset: var(--focus-offset);
}
.code-block::before {
content: 'CODE';
position: absolute;
top: -6px;
right: 15px;
background: var(--color-primary);
color: white;
padding: 10px 8px 0;
font-size: 0.7rem;
border-radius: 4px;
font-weight: 600;
}
.pros-cons {
margin: 1.5rem 0;
}
.pros-cons h4 {
margin-bottom: 1rem;
color: var(--color-text);
font-size: 1rem;
font-weight: 600;
}
.pros-cons ul {
list-style: none;
padding-left: 0;
}
.pros-cons li {
padding: 0.5rem 0;
padding-left: 1.5rem;
position: relative;
}
.pros li::before {
content: '✓';
position: absolute;
left: 0;
color: var(--color-primary);
font-weight: bold;
}
.cons li::before {
content: '✗';
position: absolute;
left: 0;
color: var(--color-danger);
font-weight: bold;
}
/* Interactive Elements */
.js-collapsible {
background: var(--color-danger);
color: white;
cursor: pointer;
padding: 12px 16px;
border: none;
text-align: left;
outline: none;
font-size: 1rem;
border-radius: var(--radius);
margin-bottom: 1rem;
width: 100%;
transition: all 0.2s ease;
font-family: inherit;
font-weight: 500;
}
.js-collapsible:hover {
background: #c82333;
transform: translateY(-1px);
}
.js-collapsible:focus {
outline: var(--focus-outline-danger);
outline-offset: var(--focus-offset);
}
.js-content {
padding: 0;
display: none;
background: var(--color-content-bg);
border: 1px solid var(--color-border);
border-radius: 0 0 var(--radius) var(--radius);
margin-bottom: 1rem;
transition: all 0.2s ease;
}
.js-content.active {
display: block;
padding: 16px;
}
details {
background: var(--color-card);
border: 1px solid var(--color-border);
border-radius: var(--radius);
margin-bottom: 1rem;
overflow: hidden;
}
details:focus-within {
outline: var(--focus-outline);
outline-offset: var(--focus-offset);
}
summary {
background: var(--color-primary);
color: white;
padding: 12px 16px;
cursor: pointer;
font-size: 1rem;
list-style: none;
font-weight: 500;
transition: all 0.2s ease;
}
summary:hover {
background: var(--color-primary-hover);
}
summary:focus {
outline: var(--focus-outline);
outline-offset: -2px;
}
summary::-webkit-details-marker {
display: none;
}
summary::before {
content: '▶';
margin-right: 8px;
transition: transform 0.2s ease;
display: inline-block;
}
details[open] summary::before {
transform: rotate(90deg);
}
details > div {
padding: 16px;
background: var(--color-content-bg);
}
/* Modal Styles */
.js-modal-overlay {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.6);
z-index: 1000;
}
.js-modal-overlay.active {
display: flex;
align-items: center;
justify-content: center;
}
.js-modal-content {
background: var(--color-bg);
padding: 2rem;
border-radius: var(--radius);
max-width: 500px;
width: 90%;
border: 1px solid var(--color-border);
box-shadow: var(--shadow);
}
.js-modal-content:focus {
outline: var(--focus-outline-danger);
outline-offset: var(--focus-offset);
}
dialog {
border: 1px solid var(--color-border);
border-radius: var(--radius);
padding: 2rem;
background: var(--color-bg);
color: var(--color-text);
box-shadow: var(--shadow);
max-width: 500px;
width: 90%;
}
dialog:focus {
outline: var(--focus-outline);
outline-offset: var(--focus-offset);
}
dialog::backdrop {
background: rgba(0, 0, 0, 0.6);
}
/* Form Styles */
.form-group {
margin-bottom: 1.5rem;
}
.form-group label {
display: block;
margin-bottom: 0.5rem;
font-weight: 500;
color: var(--color-text);
}
.form-group input, .form-group textarea, .form-group select {
width: 100%;
padding: 10px 12px;
border: 1px solid var(--color-border);
border-radius: var(--radius);
font-size: 1rem;
background: var(--color-bg);
color: var(--color-text);
transition: all 0.2s ease;
font-family: inherit;
}
.form-group input:focus, .form-group textarea:focus, .form-group select:focus {
outline: var(--focus-outline);
outline-offset: -2px;
border-color: var(--color-primary);
}
.form-group input:invalid {
border-color: var(--color-danger);
}
.form-group input:valid {
border-color: var(--color-primary);
}
.js-error {
color: var(--color-danger);
font-size: 0.875rem;
margin-top: 0.5rem;
display: none;
}
.js-error.active {
display: block;
}
/* Progress Styles */
.js-progress-container {
width: 100%;
background: var(--color-border);
border-radius: 4px;
height: 20px;
margin: 1.5rem 0;
overflow: hidden;
}
.js-progress-bar {
height: 100%;
background: var(--color-danger);
width: 0;
transition: width 0.3s ease;
border-radius: 4px;
}
progress {
width: 100%;
height: 20px;
margin: 1.5rem 0;
border-radius: 4px;
border: none;
background: var(--color-border);
}
progress:focus {
outline: var(--focus-outline);
outline-offset: var(--focus-offset);
}
progress::-webkit-progress-bar {
background-color: var(--color-border);
border-radius: 4px;
}
progress::-webkit-progress-value {
background: var(--color-primary);
border-radius: 4px;
}
progress::-moz-progress-bar {
background: var(--color-primary);
border-radius: 4px;
}
/* Button Styles */
button {
background: var(--color-primary);
color: white;
border: none;
padding: 10px 16px;
border-radius: var(--radius);
cursor: pointer;
font-size: 1rem;
margin: 0.5rem 0.5rem 0.5rem 0;
font-weight: 500;
transition: all 0.2s ease;
font-family: inherit;
}
button:hover {
background: var(--color-primary-hover);
transform: translateY(-1px);
}
button:focus {
outline: var(--focus-outline);
outline-offset: var(--focus-offset);
}
button:disabled {
background: var(--color-text-muted);
cursor: not-allowed;
transform: none;
}
/* Component Styles */
.datalist-container {
position: relative;
}
input[list] {
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%23666' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3e%3c/svg%3e");
background-position: right 12px center;
background-repeat: no-repeat;
background-size: 16px;
padding-right: 36px;
}
.slider-container {
margin: 2rem 0;
}
input[type="range"] {
width: 100%;
height: 6px;
border-radius: 3px;
background: var(--color-border);
outline: none;
-webkit-appearance: none;
}
input[type="range"]:focus {
outline: var(--focus-outline);
outline-offset: var(--focus-offset);
}
input[type="range"]::-webkit-slider-thumb {
appearance: none;
width: 18px;
height: 18px;
border-radius: 50%;
background: var(--color-primary);
cursor: pointer;
}
input[type="range"]::-moz-range-thumb {
width: 18px;
height: 18px;
border-radius: 50%;
background: var(--color-primary);
cursor: pointer;
border: none;
}
.color-input {
width: 50px;
height: 32px;
border: 1px solid var(--color-border);
border-radius: var(--radius);
cursor: pointer;
}
.color-input:focus {
outline: var(--focus-outline);
outline-offset: var(--focus-offset);
}
.summary-box {
margin-top: 4rem;
padding: 2rem;
background: var(--color-card);
border-radius: var(--radius);
box-shadow: var(--shadow);
border: 1px solid var(--color-border);
text-align: center;
}
.summary-box h3 {
font-size: 1.5rem;
margin-bottom: 1rem;
color: var(--color-primary);
font-weight: 600;
}
.zen-quote {
font-style: italic;
color: var(--color-text-muted);
font-size: 1rem;
margin-top: 1.5rem;
border-left: 3px solid var(--color-primary);
padding-left: 1rem;
}
@media (max-width: 768px) {
.comparison-grid {
grid-template-columns: 1fr;
}
body {
padding: 1rem;
}
.hero {
padding: 2rem;
}
.section-title {
font-size: 1.75rem;
}
}
/* Performance indicators */
.perf-indicator {
display: inline-block;
padding: 2px 6px;
border-radius: 4px;
font-size: 0.75rem;
font-weight: 600;
margin-left: 8px;
}
.perf-fast {
background: rgba(0, 102, 204, 0.1);
color: var(--color-primary);
}
.perf-slow {
background: rgba(220, 53, 69, 0.1);
color: var(--color-danger);
}
</style>
</head>
<body class="search_plugin_added">
<div class="hero">
<h1>🚀 Built-in HTML Components</h1>
<p class="subtitle">Discover the power of semantic HTML and native browser features. This guide shows you how to build accessible, performant interfaces using the web platform's built-in components with progressive enhancement.</p>
</div>
<!-- COLLAPSIBLES -->
<div class="section">
<h2 class="section-title">🎯 Collapsible Content</h2>
<div class="comparison-grid">
<div class="column bad">
<h3>Custom Implementation <span class="perf-indicator perf-slow">COMPLEX</span></h3>
<div class="accessibility-note">
<strong>⚠️ Accessibility:</strong> Requires manual ARIA, keyboard nav, and screen reader support.
</div>
<button class="js-collapsible" onclick="toggleContent('content1')">
What is Web Accessibility?
</button>
<div class="js-content" id="content1">
Web accessibility ensures that websites work for people with disabilities. Custom implementations need careful attention to accessibility requirements.
</div>
<button class="js-collapsible" onclick="toggleContent('content2')">
Why WCAG Guidelines Matter
</button>
<div class="js-content" id="content2">
WCAG provides the framework for accessible web content. Following these guidelines ensures your content works for assistive technologies.
</div>
<div class="pros-cons">
<h4 class="cons">❌ Implementation Challenges:</h4>
<ul>
<li>Manual ARIA attributes and keyboard navigation</li>
<li>JavaScript dependency affects reliability</li>
<li>State management and performance overhead</li>
</ul>
</div>
</div>
<div class="column good">
<h3>Native HTML Elements <span class="perf-indicator perf-fast">BUILT-IN</span></h3>
<div class="accessibility-note">
<strong>🎯 Built-in:</strong> ARIA support, keyboard navigation, screen reader compatibility work automatically.
</div>
<details>
<summary>What is Web Accessibility?</summary>
<div>
Web accessibility ensures that websites work for people with disabilities. Native HTML elements provide accessibility features automatically, following established web standards.
</div>
</details>
<details>
<summary>Why WCAG Guidelines Matter</summary>
<div>
WCAG provides the framework for accessible web content. Native elements follow these guidelines by default, reducing development complexity.
</div>
</details>
<details>
<summary>Progressive Enhancement Benefits</summary>
<div>
Start with functional HTML, enhance with CSS, add JavaScript where needed. This ensures your content works across all devices and abilities.
</div>
</details>
<div class="pros-cons">
<h4 class="pros">✅ Built-in Advantages:</h4>
<ul>
<li>Semantic HTML5 with native ARIA and keyboard support</li>
<li>Works without JavaScript - progressive enhancement</li>
<li>Zero maintenance overhead, consistent UX</li>
</ul>
</div>
</div>
</div>
</div>
<!-- MODALS -->
<div class="section">
<h2 class="section-title">🪟 Modal Dialogs</h2>
<div class="comparison-grid">
<div class="column bad">
<h3>Custom Modal Implementation <span class="perf-indicator perf-slow">INVOLVED</span></h3>
<div class="accessibility-note">
<strong>⚠️ Requirements:</strong> Focus trapping, ESC handling, backdrop interaction, ARIA roles need custom development.
</div>
<button onclick="openJSModal()">Open Custom Modal</button>
<div class="js-modal-overlay" id="jsModal">
<div class="js-modal-content">
<h4>Custom Modal Implementation</h4>
<p>This modal requires custom JavaScript for focus management, keyboard handling, and ARIA attributes. While flexible, it needs careful implementation.</p>
<button onclick="closeJSModal()">Close Modal</button>
</div>
</div>
<div class="pros-cons">
<h4 class="cons">❌ Development Requirements:</h4>
<ul>
<li>Focus trapping and ESC key handling</li>
<li>ARIA attributes and scroll management</li>
<li>Event cleanup and comprehensive testing</li>
</ul>
</div>
</div>
<div class="column good">
<h3>Native Dialog Element <span class="perf-indicator perf-fast">READY</span></h3>
<div class="accessibility-note">
<strong>🎯 Built-in:</strong> Focus trapping, ESC support, backdrop clicks, ARIA roles work out of the box.
</div>
<button onclick="document.getElementById('nativeDialog').showModal()">
Open Native Dialog
</button>
<dialog id="nativeDialog">
<h4>Native Dialog Element</h4>
<p>This dialog provides built-in focus trapping, keyboard support, backdrop interaction, and ARIA semantics automatically.</p>
<p><strong>The browser handles the complexity for you.</strong></p>
<button onclick="document.getElementById('nativeDialog').close()">
Close Dialog
</button>
</dialog>
<div class="pros-cons">
<h4 class="pros">✅ Native Features:</h4>
<ul>
<li>Built-in focus trapping and ESC key support</li>
<li>Backdrop clicks and scroll management</li>
<li>No memory leaks, consistent browser behavior</li>
</ul>
</div>
</div>
</div>
</div>
<!-- FORM VALIDATION -->
<div class="section">
<h2 class="section-title">📝 Form Validation</h2>
<div class="comparison-grid">
<div class="column bad">
<h3>Custom Validation Logic <span class="perf-indicator perf-slow">MANUAL</span></h3>
<div class="accessibility-note">
<strong>⚠️ Implementation:</strong> Custom error announcements, validation timing, focus management needed.
</div>
<form onsubmit="return validateJSForm(event)">
<div class="form-group">
<label for="js-email">Email Address</label>
<input id="js-email" name="email" type="text">
<div class="js-error" id="email-error">Please enter a valid email</div>
</div>
<div class="form-group">
<label for="js-iban">IBAN</label>
<input id="js-iban" name="iban" type="text">
<div class="js-error" id="iban-error">Please enter a valid IBAN</div>
</div>
<button type="submit">Submit Form</button>
</form>
<div class="pros-cons">
<h4 class="cons">❌ Custom Validation Challenges:</h4>
<ul>
<li>Custom patterns may miss edge cases</li>
<li>Error message and timing management</li>
<li>Client-server validation synchronization</li>
</ul>
</div>
</div>
<div class="column good">
<h3>Native HTML5 Validation <span class="perf-indicator perf-fast">INTEGRATED</span></h3>
<div class="accessibility-note">
<strong>🎯 Built-in:</strong> Automatic error announcements, ARIA attributes, consistent validation timing.
</div>
<form>
<div class="form-group">
<label for="native-email-wcag">Email Address</label>
<input id="native-email-wcag" name="email" placeholder="user@example.com" required="" type="email">
</div>
<div class="form-group">
<label for="native-iban">IBAN</label>
<input id="native-iban" name="iban"
pattern="[A-Z]{2}[0-9]{2}[A-Z0-9]{4}[0-9]{7}([A-Z0-9]?){0,16}"
placeholder="DE89370400440532013000" required=""
title="Enter a valid IBAN format (e.g., DE89370400440532013000)" type="text">
</div>
<div class="form-group">
<label for="native-url">Website URL</label>
<input id="native-url" name="website" placeholder="https://example.com" type="url">
</div>
<button type="submit">Submit Form</button>
</form>
<div class="pros-cons">
<h4 class="pros">✅ Native Validation Features:</h4>
<ul>
<li>Built-in validation for email, URL, patterns</li>
<li>Automatic error messages in user's language</li>
<li>CSS pseudo-classes and Constraint Validation API</li>
</ul>
</div>
</div>
</div>
</div>
<!-- PROGRESS INDICATORS -->
<div class="section">
<h2 class="section-title">📊 Progress Indicators</h2>
<div class="comparison-grid">
<div class="column bad">
<h3>Custom Progress Implementation <span class="perf-indicator perf-slow">STYLED</span></h3>
<div class="accessibility-note">
<strong>⚠️ Requirements:</strong> Semantic meaning, screen reader announcements, ARIA labels need custom implementation.
</div>
<div class="js-progress-container">
<div class="js-progress-bar" id="jsProgress"></div>
</div>
<p>Custom Progress: <span id="jsProgressText">0%</span></p>
<button onclick="startJSProgress()">Start Progress Demo</button>
<div class="pros-cons">
<h4 class="cons">❌ Custom Implementation Needs:</h4>
<ul>
<li>No semantic meaning without ARIA attributes</li>
<li>Screen reader announcements require setup</li>
<li>Animation performance and value calculations</li>
</ul>
</div>
</div>
<div class="column good">
<h3>Native Progress Element <span class="perf-indicator perf-fast">SEMANTIC</span></h3>
<div class="accessibility-note">
<strong>🎯 Built-in:</strong> Semantic element, native ARIA support, automatic screen reader announcements.
</div>
<progress id="nativeProgress" max="100" value="0">0%</progress>
<p>Native Progress: <span id="nativeProgressText">0%</span></p>
<button onclick="startNativeProgress()">Start Progress Demo</button>
<progress max="100" value="70">70%</progress>
<p>Static Progress Example</p>
<progress>Loading...</progress>
<p>Indeterminate Progress (no value attribute)</p>
<div class="pros-cons">
<h4 class="pros">✅ Native Progress Benefits:</h4>
<ul>
<li>Semantic element with built-in ARIA support</li>
<li>Automatic progress announcements</li>
<li>Indeterminate state and hardware-accelerated animations</li>
</ul>
</div>
</div>
</div>
</div>
<!-- DATE PICKERS -->
<div class="section">
<h2 class="section-title">📅 Date Pickers</h2>
<div class="comparison-grid">
<div class="column bad">
<h3>Custom Date Picker <span class="perf-indicator perf-slow">LIBRARY</span></h3>
<div class="accessibility-note">
<strong>⚠️ Complexity:</strong> Keyboard navigation, screen reader support, date parsing, mobile UX need development.
</div>
<div class="form-group">
<label for="js-date">Select Date (Custom)</label>
<input id="js-date" onclick="openDatePicker()" placeholder="DD.MM.YYYY" readonly="" type="text">
<div id="datePicker"
style="display:none; position:absolute; background:white; border:1px solid #ccc; z-index:1000;">
<p style="padding:20px; color:#666;">
[Complex calendar widget would be here]<br>
Requires: JavaScript library, keyboard handlers,<br>
ARIA implementation, mobile touch events.
</p>
</div>
</div>
<div class="pros-cons">
<h4 class="cons">❌ Custom Date Picker Challenges:</h4>
<ul>
<li>Large JavaScript libraries and complex keyboard navigation</li>
<li>Mobile UX differs from native experience</li>
<li>Date format parsing, timezone, and localization complexity</li>
</ul>
</div>
</div>
<div class="column good">
<h3>Native Date Inputs <span class="perf-indicator perf-fast">PLATFORM</span></h3>
<div class="accessibility-note">
<strong>🎯 Platform:</strong> Native keyboard navigation, screen reader support, platform-consistent UX, automatic validation.
</div>
<div class="form-group">
<label for="native-date">Date</label>
<input id="native-date" max="2030-12-31" min="2020-01-01" name="date" type="date" value="2024-06-15">
</div>
<div class="form-group">
<label for="native-datetime">Date and Time</label>
<input id="native-datetime" max="2024-12-31T23:59" min="2024-01-01T00:00" name="datetime" type="datetime-local">
</div>
<div class="form-group">
<label for="native-time">Time</label>
<input id="native-time" max="17:00" min="09:00" name="time" step="900" type="time">
</div>
<div class="pros-cons">
<h4 class="pros">✅ Native Date Input Benefits:</h4>
<ul>
<li>No JavaScript required - native OS picker on mobile</li>
<li>Automatic keyboard navigation and date validation</li>
<li>Consistent UX and automatic localization</li>
</ul>
</div>
</div>
</div>
</div>
<!-- SEARCH & AUTOCOMPLETE -->
<div class="section">
<h2 class="section-title">🔍 Search &amp; Autocomplete</h2>
<div class="comparison-grid">
<div class="column bad">
<h3>Custom Autocomplete <span class="perf-indicator perf-slow">FEATURED</span></h3>
<div class="accessibility-note">
<strong>⚠️ Requirements:</strong> Dropdown management, keyboard navigation, screen reader support, focus management.
</div>
<div class="form-group">
<label for="js-search">City Search (Custom)</label>
<input autocomplete="off" id="js-search" onkeyup="filterCities(this.value)"
placeholder="Type to search cities..." type="text">
<div id="js-results"
style="display:none; position:absolute; background:var(--color-card); border:1px solid var(--color-border); max-height:200px; overflow-y:auto; z-index:100;">
</div>
</div>
<div class="pros-cons">
<h4 class="cons">❌ Custom Autocomplete Requirements:</h4>
<ul>
<li>Complex keyboard navigation and ARIA management</li>
<li>Focus management and dropdown positioning</li>
<li>Mobile touch behavior and performance considerations</li>
</ul>
</div>
</div>
<div class="column good">
<h3>Native Datalist Element <span class="perf-indicator perf-fast">BUILT-IN</span></h3>
<div class="accessibility-note">
<strong>🎯 Native:</strong> Built-in keyboard navigation, screen reader support, native OS integration.
</div>
<div class="form-group">
<label for="native-city">City Search (Native)</label>
<input id="native-city" list="cities" placeholder="Type or select a city..." type="text">
<datalist id="cities">
<option value="Berlin">
</option>
<option value="Vienna">
</option>
<option value="Zurich">
</option>
<option value="Munich">
</option>
<option value="Hamburg">
</option>
<option value="Salzburg">
</option>
<option value="Geneva">
</option>
<option value="Frankfurt">
</option>
<option value="Cologne">
</option>
<option value="Stuttgart">
</option>
</datalist>
</div>
<div class="form-group">
<label for="native-browser">Browser Choice</label>
<input id="native-browser" list="browsers" placeholder="Choose your browser..." type="text">
<datalist id="browsers">
<option label="Google Chrome" value="Chrome">
</option>
<option label="Mozilla Firefox" value="Firefox">
</option>
<option label="Apple Safari" value="Safari">
</option>
<option label="Microsoft Edge" value="Edge">
</option>
<option label="Opera Browser" value="Opera">
</option>
</datalist>
</div>
<div class="form-group">
<label for="native-company">Company Domain</label>
<input id="native-company" list="company-domains" placeholder="company-name" type="text">
<datalist id="company-domains">
<option value="siemens">
</option>
<option value="volkswagen">
</option>
<option value="bmw">
</option>
<option value="mercedes-benz">
</option>
<option value="bosch">
</option>
</datalist>
</div>
<div class="pros-cons">
<h4 class="pros">✅ Native Datalist Features:</h4>
<ul>
<li>Zero JavaScript - built-in keyboard navigation</li>
<li>Screen reader compatible with native OS integration</li>
<li>Form validation compatibility and graceful degradation</li>
</ul>
</div>
</div>
</div>
</div>
<div class="summary-box">
<h3>Embrace Built-in Web Components</h3>
<p>Native HTML elements provide rich functionality with built-in accessibility, keyboard navigation, and consistent user experience. These elements represent years of browser engineering and web standards development.</p>
<p><strong>The approach:</strong></p>
<ul style="text-align: left; max-width: 600px; margin: 2rem auto;">
<li>Start with semantic HTML that works for everyone</li>
<li>Enhance with CSS for visual design</li>
<li>Add JavaScript progressively where truly needed</li>
</ul>
<p>Build with the platform, not against it. <strong>Your users will thank you.</strong></p>
<div class="zen-quote">
"The most elegant code leverages existing solutions. Native HTML elements provide decades of accessibility research and browser optimization - use them as your foundation."
</div>
</div>
<script>
// Existing JavaScript functions with additions for progress demo
function startNativeProgress() {
const progress = document.getElementById('nativeProgress');
const text = document.getElementById('nativeProgressText');
let value = 0;
const interval = setInterval(() => {
value += Math.random() * 15;
if (value >= 100) {
value = 100;
clearInterval(interval);
}
progress.value = value;
text.textContent = Math.round(value) + '%';
}, 200);
}
// Rest of existing JavaScript functions remain unchanged
function toggleContent(id) {
const content = document.getElementById(id);
content.style.display = content.style.display === 'none' ? 'block' : 'none';
}
function openJSModal() {
document.getElementById('jsModal').style.display = 'flex';
}
function closeJSModal() {
document.getElementById('jsModal').style.display = 'none';
}
function validateJSForm(event) {
event.preventDefault();
alert('Custom validation would run here');
return false;
}
function startJSProgress() {
const bar = document.getElementById('jsProgress');
const text = document.getElementById('jsProgressText');
let width = 0;
const interval = setInterval(() => {
width += Math.random() * 15;
if (width >= 100) {
width = 100;
clearInterval(interval);
}
bar.style.width = width + '%';
text.textContent = Math.round(width) + '%';
}, 200);
}
function openDatePicker() {
const picker = document.getElementById('datePicker');
picker.style.display = picker.style.display === 'none' ? 'block' : 'none';
}
const cities = [
// Original core cities with proper names
'Berlin', 'Wien', 'Zürich', 'München', 'Hamburg', 'Salzburg', 'Genève', 'Frankfurt am Main', 'Köln', 'Stuttgart',
// Extended German cities
'Dresden', 'Leipzig', 'Düsseldorf', 'Dortmund', 'Essen', 'Bremen', 'Hannover', 'Nürnberg', 'Duisburg', 'Bochum',
'Wuppertal', 'Bielefeld', 'Bonn', 'Münster', 'Karlsruhe', 'Mannheim', 'Augsburg', 'Wiesbaden', 'Gelsenkirchen', 'Mönchengladbach',
'Braunschweig', 'Chemnitz', 'Kiel', 'Aachen', 'Halle (Saale)', 'Magdeburg', 'Freiburg im Breisgau', 'Krefeld', 'Lübeck', 'Oberhausen',
// Austrian cities beyond Wien/Salzburg
'Graz', 'Linz', 'Innsbruck', 'Klagenfurt', 'Villach', 'Wels', 'Sankt Pölten', 'Dornbirn', 'Steyr', 'Wiener Neustadt',
// Swiss cities beyond Zürich/Genève
'Basel', 'Bern', 'Lausanne', 'Winterthur', 'Luzern', 'St. Gallen', 'Lugano', 'Biel/Bienne', 'Thun', 'Köniz',
// South Tyrolean cities (Italian with German names)
'Bozen', 'Meran', 'Brixen', 'Bruneck', 'Sterzing', 'Schlanders', 'Eppan', 'Leifers', 'Klausen', 'Neumarkt',
// Alsatian cities (historically German-speaking)
'Strasbourg', 'Mulhouse', 'Colmar', 'Haguenau', 'Schiltigheim', 'Illkirch-Graffenstaden', 'Saint-Louis', 'Sélestat', 'Bischwiller', 'Saverne'
];
function filterCities(value) {
const results = document.getElementById('js-results');
if (!value) {
results.style.display = 'none';
return;
}
const filtered = cities.filter(city =>
city.toLowerCase().includes(value.toLowerCase())
);
results.innerHTML = filtered.map(city =>
`<div style="padding:8px; cursor:pointer;" onclick="selectCity('${city}')">${city}</div>`
).join('');
results.style.display = filtered.length ? 'block' : 'none';
}
function selectCity(city) {
document.getElementById('js-search').value = city;
document.getElementById('js-results').style.display = 'none';
}
</script>
</body>
</html>