Liveweave: Generative AI Web Editor & HTML/CSS/JS Playground
Initializing
Liveweave
Web
expand_more
home
Home
Palette
Color Explorer
arrow_outward
Polyline
Graphics Editor
arrow_outward
frame_source
Python Playground
arrow_outward
build
Tools
expand_more
restart_alt
Load "Hello Weaver!"
post_add
Generate Lorem ipsum...
code
Format HTML
code_blocks
Format CSS
data_object
Format JavaScript
library_add
Library
expand_more
A
Algolia JS
Animate CSS
Apex Charts JS
B
Bulma CSS
Bootstrap
C
Chart JS
Chartist
Create JS
D
D3
Dojo
F
Foundation
Fullpage JS
G
Granim JS
Google Charts
H
Halfmoon
J
jQuery
M
Materialize
Moment JS
Masonry JS
Milligram CSS
P
Pure CSS
Primer CSS
Popper JS
Pattern CSS
Picnic CSS
R
React JS
Raphael JS
Raisin CSS
S
Semantic UI
Skeleton CSS
Spectre CSS
Tachyons CSS
T
Tailwind
Three JS
U
UI Kit
Vis JS
W
Water CSS
download
Download
expand_more
developer_mode
Download as HTML
folder_zip
Download as .ZIP
cloud_upload
Fork
account_circle
Login
settings
Settings
expand_more
Editor font
14
px
A
A
Night mode
Line number
Mini map
Word wrap
sync_alt
Reset Settings
smart_display
Run
left_panel_close
AI Assistant
dashboard
All
HTML
CSS
JS
visibility
Preview
bolt
Live Preview
terminal
JS Console
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Interactive Search</title> </head> <body> <div class="page"> <div class="top-line"> <span>ARCHIVE / 001</span> <span>SEARCH INTERFACE</span> <span id="clock">00:00:00</span> </div> <header class="hero"> <div class="hero-number">01</div> <div> <div class="kicker">FIND YOUR NEXT IDEA</div> <h1> Search<br> Everything. </h1> </div> </header> <section class="search-area"> <div class="search-label"> QUERY </div> <!-- Search wrapper --> <div class="search-wrapper" id="searchWrapper" > <!-- Search input --> <div class="search-box" id="searchBox" > <div class="search-symbol"> / </div> <input id="searchInput" type="text" placeholder="Type something..." autocomplete="off" spellcheck="false" > <div class="search-meta"> <span class="result-total" id="resultCount" > — </span> <span class="key"> ENTER </span> </div> </div> <!-- Dropdown --> <div class="search-dropdown" id="searchDropdown" > <div class="dropdown-header"> <span id="dropdownLabel"> SUGGESTED </span> <span> ↑ ↓ </span> </div> <div class="results" id="results" ></div> <div class="empty" id="empty" > <div class="empty-number"> 404 </div> <div> NOTHING HERE. </div> <small> Try a different phrase. </small> </div> <div class="dropdown-footer"> <span> ENTER TO OPEN </span> <span> ESC TO CLOSE </span> </div> </div> </div> <!-- Filters remain outside dropdown --> <div class="filters"> <button class="filter active" data-filter="All"> ALL </button> <button class="filter" data-filter="Projects"> PROJECTS </button> <button class="filter" data-filter="Design"> DESIGN </button> <button class="filter" data-filter="People"> PEOPLE </button> <button class="filter" data-filter="Places"> PLACES </button> </div> </section> <footer> <span>↑ ↓ NAVIGATE</span> <span>ENTER OPEN</span> <span>ESC CLOSE</span> <span class="footer-right"> <span id="resultIndicator"> READY </span> </span> </footer> </div> </body> </html>
* { box-sizing: border-box; } html, body { margin: 0; width: 100%; height: 100%; } body { background: #f2efe7; color: #111; font-family: Arial, Helvetica, sans-serif; overflow-x: hidden; } /* ========================================= PAPER TEXTURE ========================================= */ body::before { content: ""; position: fixed; inset: 0; pointer-events: none; opacity: 0.15; background-image: radial-gradient( rgba(0,0,0,0.25) 0.6px, transparent 0.6px ); background-size: 5px 5px; z-index: 20; } /* ========================================= PAGE ========================================= */ .page { width: min(1050px, calc(100% - 60px)); min-height: 100vh; margin: auto; display: flex; flex-direction: column; } /* ========================================= TOP LINE ========================================= */ .top-line { display: grid; grid-template-columns: 1fr 1fr 1fr; padding: 18px 0 13px; border-bottom: 2px solid #111; font-size: 9px; font-weight: bold; letter-spacing: 1.5px; } .top-line span:nth-child(2) { text-align: center; } .top-line span:last-child { text-align: right; } /* ========================================= HERO ========================================= */ .hero { display: grid; grid-template-columns: 100px 1fr; gap: 25px; padding: 55px 0 45px; } .hero-number { padding-top: 8px; font-size: 16px; font-weight: bold; color: #f04b23; } .kicker { margin-bottom: 12px; font-size: 10px; font-weight: bold; letter-spacing: 3px; } h1 { margin: 0; font-size: clamp(58px, 9vw, 108px); line-height: 0.82; letter-spacing: -7px; font-weight: 800; } /* ========================================= SEARCH AREA ========================================= */ .search-area { margin-top: 10px; } .search-label { margin-bottom: 10px; font-size: 10px; font-weight: bold; letter-spacing: 2px; } /* ========================================= SEARCH WRAPPER ========================================= */ .search-wrapper { position: relative; z-index: 30; } /* ========================================= SEARCH BOX ========================================= */ .search-box { position: relative; height: 92px; display: flex; align-items: center; background: white; border: 3px solid #111; box-shadow: 10px 10px 0 #111; transition: transform 0.18s ease, box-shadow 0.18s ease; } .search-wrapper.open .search-box { transform: translate(3px, 3px); box-shadow: 7px 7px 0 #f04b23; } .search-symbol { width: 75px; height: 100%; display: flex; align-items: center; justify-content: center; border-right: 2px solid #111; font-size: 30px; font-weight: bold; color: #f04b23; transition: transform 0.2s ease; } .search-wrapper.open .search-symbol { transform: rotate(-8deg); } #searchInput { flex: 1; width: 100%; height: 100%; padding: 0 20px; border: none; outline: none; background: transparent; color: #111; font-size: 28px; font-weight: bold; letter-spacing: -1px; } #searchInput::placeholder { color: #aaa59d; } .search-meta { display: flex; align-items: center; gap: 12px; padding-right: 18px; } .result-total { font-size: 11px; font-weight: bold; } .key { padding: 6px 8px; border: 1px solid #111; font-size: 8px; font-weight: bold; } /* ========================================= SEARCH DROPDOWN ========================================= */ .search-dropdown { position: absolute; left: 0; right: 0; top: calc(100% + 8px); background: #fff; border: 3px solid #111; box-shadow: 10px 10px 0 #111; opacity: 0; transform: translateY(-8px) scaleY(0.96); transform-origin: top; pointer-events: none; visibility: hidden; transition: opacity 0.18s ease, transform 0.18s ease, visibility 0.18s ease; } .search-wrapper.open .search-dropdown { opacity: 1; transform: translateY(0) scaleY(1); pointer-events: auto; visibility: visible; } /* ========================================= DROPDOWN HEADER ========================================= */ .dropdown-header { height: 40px; display: flex; align-items: center; justify-content: space-between; padding: 0 14px; border-bottom: 2px solid #111; background: #f2efe7; font-size: 8px; font-weight: bold; letter-spacing: 1.5px; } /* ========================================= RESULTS ========================================= */ .results { max-height: 340px; overflow-y: auto; } .result { display: grid; grid-template-columns: 42px 1fr auto; gap: 14px; align-items: center; min-height: 78px; padding: 12px 14px; border-bottom: 1px solid #d1ccc4; cursor: pointer; transition: background 0.12s ease, padding-left 0.12s ease; } .result:hover, .result.selected { background: #f04b23; color: white; padding-left: 20px; } .result-index { font-size: 9px; font-weight: bold; color: #aaa59d; } .result:hover .result-index, .result.selected .result-index { color: white; } .result-title { font-size: 14px; font-weight: bold; } .result-title mark { background: #ffe16a; color: #111; padding: 1px 2px; } .result-description { margin-top: 4px; font-size: 10px; line-height: 1.4; color: #77736c; } .result:hover .result-description, .result.selected .result-description { color: rgba(255,255,255,0.82); } .result-category { padding: 5px 7px; border: 1px solid #bbb6ae; font-size: 7px; font-weight: bold; letter-spacing: 1px; } .result:hover .result-category, .result.selected .result-category { border-color: rgba(255,255,255,0.6); } /* ========================================= EMPTY ========================================= */ .empty { display: none; padding: 35px 18px; text-align: center; } .empty.visible { display: block; } .empty-number { margin-bottom: 12px; font-size: 50px; font-weight: 800; letter-spacing: -4px; color: #f04b23; } .empty div:not(.empty-number) { font-size: 13px; font-weight: bold; } .empty small { display: block; margin-top: 5px; font-size: 9px; color: #777; } /* ========================================= DROPDOWN FOOTER ========================================= */ .dropdown-footer { display: flex; justify-content: space-between; padding: 9px 14px; background: #111; color: white; font-size: 7px; font-weight: bold; letter-spacing: 1px; } /* ========================================= FILTERS ========================================= */ .filters { display: flex; flex-wrap: wrap; gap: 7px; margin-top: 18px; } .filter { padding: 8px 12px; border: 1.5px solid #111; background: transparent; font-size: 9px; font-weight: bold; cursor: pointer; transition: transform 0.15s ease, background 0.15s ease, color 0.15s ease; } .filter:hover { transform: translateY(-2px); } .filter.active { background: #111; color: white; } /* ========================================= FOOTER ========================================= */ footer { display: flex; gap: 25px; margin-top: auto; padding: 16px 0; border-top: 2px solid #111; font-size: 8px; font-weight: bold; letter-spacing: 1px; } .footer-right { margin-left: auto; color: #f04b23; } /* ========================================= MOBILE ========================================= */ @media (max-width: 700px) { .page { width: calc(100% - 30px); } .hero { grid-template-columns: 45px 1fr; padding: 40px 0 35px; } h1 { font-size: 57px; letter-spacing: -4px; } .search-box { height: 72px; } .search-symbol { width: 50px; } #searchInput { font-size: 20px; } .search-meta { display: none; } .result { grid-template-columns: 32px 1fr; } .result-category { display: none; } footer { gap: 12px; flex-wrap: wrap; } }
/* ========================================= SEARCH DATA ========================================= */ const data = [ { title: "Project Aurora", description: "An experimental project exploring new interaction patterns.", category: "Projects" }, { title: "Design System", description: "Components, patterns and principles for digital interfaces.", category: "Design" }, { title: "Prototype Lab", description: "A collection of experimental interface concepts.", category: "Projects" }, { title: "Maya Chen", description: "Creative technologist · San Francisco.", category: "People" }, { title: "Alex Morgan", description: "Product designer · New York.", category: "People" }, { title: "Jordan Lee", description: "Product strategist · Seattle.", category: "People" }, { title: "Research Archive", description: "Interviews, observations and usability findings.", category: "Design" }, { title: "Tokyo Studio", description: "A shared creative workspace in central Tokyo.", category: "Places" }, { title: "London Workshop", description: "Experimental design and prototyping space.", category: "Places" }, { title: "Berlin Lab", description: "A small studio focused on emerging technology.", category: "Places" }, { title: "Interface Experiments", description: "A collection of unusual interface interactions.", category: "Design" }, { title: "Future Cities", description: "Research into technology, architecture and urban life.", category: "Projects" }, { title: "Creative Coding", description: "Interactive experiments created with code.", category: "Projects" }, { title: "Visual Language", description: "Exploration of typography, layout and visual identity.", category: "Design" } ]; /* ========================================= ELEMENTS ========================================= */ const input = document.getElementById( "searchInput" ); const searchWrapper = document.getElementById( "searchWrapper" ); const results = document.getElementById( "results" ); const empty = document.getElementById( "empty" ); const resultCount = document.getElementById( "resultCount" ); const dropdownLabel = document.getElementById( "dropdownLabel" ); const resultIndicator = document.getElementById( "resultIndicator" ); const filters = document.querySelectorAll( ".filter" ); const clock = document.getElementById( "clock" ); /* ========================================= STATE ========================================= */ let activeFilter = "All"; let selectedIndex = -1; let visibleResults = []; /* ========================================= CLOCK ========================================= */ function updateClock() { const now = new Date(); clock.textContent = now.toLocaleTimeString( [], { hour12: false } ); } setInterval( updateClock, 1000 ); updateClock(); /* ========================================= OPEN SEARCH ========================================= */ input.addEventListener( "focus", function() { searchWrapper.classList.add( "open" ); resultIndicator.textContent = "SEARCHING"; renderResults(); } ); /* ========================================= TYPING ========================================= */ input.addEventListener( "input", function() { selectedIndex = -1; searchWrapper.classList.add( "open" ); renderResults(); } ); /* ========================================= FILTERS ========================================= */ filters.forEach( function(filter) { filter.addEventListener( "click", function() { filters.forEach( function(item) { item.classList.remove( "active" ); } ); filter.classList.add( "active" ); activeFilter = filter.dataset.filter; selectedIndex = -1; searchWrapper.classList.add( "open" ); renderResults(); input.focus(); } ); } ); /* ========================================= RENDER RESULTS ========================================= */ function renderResults() { const query = input.value.trim().toLowerCase(); /* Filter category first. */ visibleResults = data.filter( function(item) { const categoryMatch = activeFilter === "All" || item.category === activeFilter; /* Match title, description or category. */ const searchableText = ( item.title + " " + item.description + " " + item.category ).toLowerCase(); const textMatch = !query || searchableText.includes( query ); return ( categoryMatch && textMatch ); } ); /* Number of results. */ resultCount.textContent = visibleResults.length; /* Header label. */ if (query) { dropdownLabel.textContent = "SEARCH RESULTS"; } else { dropdownLabel.textContent = "SUGGESTED"; } /* Status. */ resultIndicator.textContent = query ? visibleResults.length + " FOUND" : "READY"; /* Empty state. */ if ( visibleResults.length === 0 ) { results.innerHTML = ""; empty.classList.add( "visible" ); return; } empty.classList.remove( "visible" ); /* Create result rows. */ results.innerHTML = visibleResults .slice(0, 8) .map( function(item, index) { return createResult( item, index, query ); } ) .join(""); updateSelection(); } /* ========================================= CREATE RESULT ========================================= */ function createResult( item, index, query ) { let title = escapeHtml( item.title ); /* Highlight search phrase. */ if (query) { const regex = new RegExp( "(" + escapeRegExp(query) + ")", "ig" ); title = title.replace( regex, "<mark>$1</mark>" ); } return ` <div class="result" data-index="${index}" data-title="${escapeHtml(item.title)}" > <div class="result-index"> ${String(index + 1).padStart(2, "0")} </div> <div> <div class="result-title"> ${title} </div> <div class="result-description"> ${escapeHtml(item.description)} </div> </div> <div class="result-category"> ${escapeHtml(item.category)} </div> </div> `; } /* ========================================= KEYBOARD NAVIGATION ========================================= */ input.addEventListener( "keydown", function(event) { const items = results.querySelectorAll( ".result" ); /* DOWN */ if ( event.key === "ArrowDown" ) { event.preventDefault(); if ( items.length === 0 ) { return; } selectedIndex = Math.min( selectedIndex + 1, items.length - 1 ); updateSelection(); } /* UP */ if ( event.key === "ArrowUp" ) { event.preventDefault(); if ( items.length === 0 ) { return; } selectedIndex = Math.max( selectedIndex - 1, 0 ); updateSelection(); } /* ENTER */ if ( event.key === "Enter" ) { event.preventDefault(); if ( selectedIndex >= 0 ) { selectResult( selectedIndex ); } else if ( visibleResults.length > 0 ) { selectResult(0); } } /* ESCAPE */ if ( event.key === "Escape" ) { closeSearch(); } } ); /* ========================================= UPDATE SELECTION ========================================= */ function updateSelection() { const items = results.querySelectorAll( ".result" ); items.forEach( function(item, index) { item.classList.toggle( "selected", index === selectedIndex ); } ); /* Automatically scroll selected result into view. */ if ( selectedIndex >= 0 && items[selectedIndex] ) { items[selectedIndex].scrollIntoView({ block: "nearest" }); } } /* ========================================= CLICK RESULT ========================================= */ results.addEventListener( "click", function(event) { const result = event.target.closest( ".result" ); if (!result) { return; } selectResult( Number( result.dataset.index ) ); } ); /* ========================================= SELECT RESULT ========================================= */ function selectResult( index ) { const item = visibleResults[index]; if (!item) { return; } input.value = item.title; selectedIndex = index; resultIndicator.textContent = "OPENED"; dropdownLabel.textContent = "SELECTED"; resultCount.textContent = "✓"; updateSelection(); /* Small search-box pulse. */ document .getElementById("searchBox") .animate( [ { transform: "translate(3px, 3px)" }, { transform: "translate(0, 0)" }, { transform: "translate(3px, 3px)" } ], { duration: 220 } ); } /* ========================================= CMD/Ctrl + K ========================================= */ document.addEventListener( "keydown", function(event) { if ( ( event.metaKey || event.ctrlKey ) && event.key.toLowerCase() === "k" ) { event.preventDefault(); input.focus(); input.select(); } } ); /* ========================================= CLOSE WHEN CLICKING OUTSIDE ========================================= */ document.addEventListener( "click", function(event) { if ( !searchWrapper.contains( event.target ) ) { closeSearch(); } } ); /* ========================================= CLOSE SEARCH ========================================= */ function closeSearch() { searchWrapper.classList.remove( "open" ); selectedIndex = -1; resultIndicator.textContent = "READY"; } /* ========================================= HELPERS ========================================= */ function escapeRegExp( string ) { return string.replace( /[.*+?^${}()|[\]\\]/g, "\\$&" ); } function escapeHtml( string ) { return String(string) .replace( /&/g, "&" ) .replace( /</g, "<" ) .replace( />/g, ">" ) .replace( /"/g, """ ) .replace( /'/g, "'" ); } /* ========================================= INITIAL STATE ========================================= */ /* Important: No results are rendered visibly until the user interacts with search. */ results.innerHTML = ""; empty.classList.remove( "visible" );
terminal
JavaScript Console
Preview
Clear
close
›
Run