Stay organized with collections
Save and categorize content based on your preferences.
HTML
<main>
<header>
<h1>Lighting</h1>
<small>Find your perfect light</small>
</header>
<aside>
<form>
<select multiple="true" title="Filter results by category">
<optgroup label="New">
<option value="last 30 days">Last 30 Days</option>
<option value="last 6 months">Last 6 Months</option>
</optgroup>
<optgroup label="Lamps">
<option value="table lamps">Table Lamps</option>
<option value="desk lamps">Desk Lamps</option>
<option value="floor lamps">Floor Lamps</option>
</optgroup>
<optgroup label="Ceiling">
<option value="chandeliers">Chandeliers</option>
<option value="pendant">Pendant</option>
<option value="flush">Flush</option>
<option value="fans">Fans</option>
</optgroup>
<optgroup label="By Room">
<option value="bedroom">Bedroom</option>
<option value="dining room">Dining Room</option>
<option value="kitchen">Kitchen</option>
<option value="living room">Living Room</option>
<option value="bathroom">Bathroom</option>
<option value="entryway">Entryway</option>
<option value="outdoor">Outdoor</option>
</optgroup>
<optgroup label="Kids">
<option value="lamps">Lamps</option>
<option value="night lights">Night Lights</option>
<option value="ceiling">Ceiling</option>
</optgroup>
</select>
<fieldset>
<legend>New</legend>
<div>
<input type="checkbox" id="last-30-days" name="new" value="last 30 days">
<label for="last-30-days">Last 30 Days</label>
</div>
<div>
<input type="checkbox" id="last-6-months" name="new" value="last 6 months">
<label for="last-6-months">Last 6 Months</label>
</div>
</fieldset>
<fieldset>
<legend>Lamps</legend>
<div>
<input type="checkbox" id="table-lamps" name="lamps" value="table lamps">
<label for="table-lamps">Table Lamps</label>
</div>
<div>
<input type="checkbox" id="desk-lamps" name="lamps" value="desk lamps">
<label for="desk-lamps">Desk Lamps</label>
</div>
<div>
<input type="checkbox" id="floor-lamps" name="lamps" value="floor lamps">
<label for="floor-lamps">Floor Lamps</label>
</div>
</fieldset>
<fieldset>
<legend>Ceiling</legend>
<div>
<input type="checkbox" id="chandeliers" name="ceiling" value="chandeliers">
<label for="chandeliers">Chandeliers</label>
</div>
<div>
<input type="checkbox" id="pendant" name="ceiling" value="pendant">
<label for="pendant">Pendant</label>
</div>
<div>
<input type="checkbox" id="flush" name="ceiling" value="flush">
<label for="flush">Flush</label>
</div>
<div>
<input type="checkbox" id="fans" name="ceiling" value="fans">
<label for="fans">Fans</label>
</div>
</fieldset>
<fieldset>
<legend>By Room</legend>
<div>
<input type="checkbox" id="bedroom" name="by room" value="bedroom">
<label for="bedroom">Bedroom</label>
</div>
<div>
<input type="checkbox" id="dining-room" name="by room" value="dining room">
<label for="dining-room">Dining Room</label>
</div>
<div>
<input type="checkbox" id="kitchen" name="by room" value="kitchen">
<label for="kitchen">Kitchen</label>
</div>
<div>
<input type="checkbox" id="living-room" name="by room" value="living room">
<label for="living-room">Living Room</label>
</div>
<div>
<input type="checkbox" id="bathroom" name="by room" value="bathroom">
<label for="bathroom">Bathroom</label>
</div>
<div>
<input type="checkbox" id="entryway" name="by room" value="entryway">
<label for="entryway">Entryway</label>
</div>
<div>
<input type="checkbox" id="outdoor" name="by room" value="outdoor">
<label for="outdoor">Outdoor</label>
</div>
</fieldset>
<fieldset>
<legend>Kids</legend>
<div>
<input type="checkbox" id="lamps" name="kids" value="lamps">
<label for="lamps">Lamps</label>
</div>
<div>
<input type="checkbox" id="night-lights" name="kids" value="night lights">
<label for="night-lights">Night Lights</label>
</div>
<div>
<input type="checkbox" id="ceiling" name="kids" value="ceiling">
<label for="ceiling">Ceiling</label>
</div>
</fieldset>
</form>
<div role="status" class="sr-only" id="applied-filters"></div>
</aside>
<article>
<span class="last-30-days table-lamps"></span>
<span class="last-6-months desk-lamps"></span>
<span class="floor-lamps"></span>
<span class="last-6-months chandeliers"></span>
<span class="pendant last-6-months"></span>
<span class="flush fans"></span>
<span class="fans pendant table-lamps"></span>
<span class="bedroom"></span>
<span class="dining-room last-30-days chandeliers"></span>
<span class="kitchen lamps"></span>
<span class="living-room"></span>
<span class="bathroom living-room chandeliers desk-lamps"></span>
<span class="bathroom table-lamps desk-lamps"></span>
<span class="entryway last-30-days"></span>
<span class="outdoor desk-lamps"></span>
<span class="lamps last-30-days"></span>
<span class="night-lights table-lamps"></span>
<span class="ceiling last-30-days"></span>
<span class="floor-lamps table-lamps"></span>
<span class="floor-lamps last-6-months"></span>
<span class="dining-room last-30-days chandeliers"></span>
<span class="kitchen lamps"></span>
<span class="living-room"></span>
<span class="bathroom living-room chandeliers desk-lamps"></span>
</article>
</main>
CSS
main {
display : grid ;
grid-template-columns : max-content 1 fr ;
gap : 5 vmin ;
align-items : flex-start ;
& > header {
grid-column : 1 / -1 ;
}
@ media ( orientation : portrait ) {
grid-template-columns : 1fr ;
}
@ media ( --useSelect ) {
& > article {
grid-row : 3 ;
grid-column : 1 / -1 ;
}
}
}
article {
--size : min ( 300 px , calc ( 25 % - 2 ch ));
margin : -1 ch ;
& > span {
will-change : transform ;
background : hsl ( 0 0 % 50 % / 25 % );
border-radius : 10 px ;
inline-size : var ( --size );
block-size : 15 ch ;
margin : 1 ch ;
@media ( orientation : portrait ) {
-- size : calc ( 50 % - 2 ch );
}
@ supports ( aspect-ratio : 1 ) {
block-size : auto ;
aspect-ratio : 1 ;
}
}
}
header {
display : grid ;
gap : 1 ch ;
}
aside {
counter-reset : filters ;
& :checked {
counter-increment : filters ;
}
& # applied-filters :: before {
content : counter ( filters ) " filters " ;
}
}
fieldset : first-of-type {
margin-block-start : -5 px ;
}
[ role = "status" ] {
@media (--useSelect) {
display : none ;
}
}
. sr-only {
inline-size : 0 ;
block-size : 0 ;
overflow : hidden ;
}
JS
import 'https://unpkg.com/isotope-layout@3.0.6/dist/isotope.pkgd.min.js'
const IsotopeGrid = new Isotope ( 'article' , {
itemSelector : 'span' ,
layoutMode : 'fitRows' ,
percentPosition : true
})
const filterGrid = query => {
const { matches : motionOK } = window . matchMedia (
'(prefers-reduced-motion: no-preference)'
)
IsotopeGrid . arrange ({
filter : query ,
stagger : 25 ,
transitionDuration : motionOK ? '0.4s' : 0 ,
})
}
// takes a and returns the selection as an array
const prepareSelectOptions = element =>
Array . from ( element . selectedOptions ). reduce (( data , opt ) => {
data . push ([ opt . parentElement . label . toLowerCase (), opt . value ])
return data
}, [])
// watcher
document . querySelector ( 'select' ). addEventListener ( 'input' , e => {
let selectData = prepareSelectOptions ( e . target )
console . warn ( 'Multiselect' , selectData )
// DEMO
// isotope query assembly from checkbox selections
let query = selectData . reduce (( query , val ) => {
query . push ( '.' + val [ 1 ]. split ( ' ' ). join ( '-' ))
return query
}, []). join ( ',' )
filterGrid ( query )
// update for assistive technology
let statusRoleElement = document . querySelector ( '#applied-filters' )
let filterResults = IsotopeGrid . getFilteredItemElements (). length
statusRoleElement . style . counterSet = selectData . length
statusRoleElement . textContent = " giving " + filterResults + " results"
})
document
. querySelector ( 'aside form' )
. addEventListener ( 'input' , e => {
if ( e . target . nodeName === 'SELECT' ) return
const formData = new FormData ( document . querySelector ( 'form' ))
console . warn ( 'Checkboxes' , Array . from ( formData . entries ()))
// DEMO
// isotope query assembly from checkbox selections
let query = Array . from ( formData . values ()). reduce (( query , val ) => {
query . push ( '.' + val . split ( ' ' ). join ( '-' ))
return query
}, []). join ( ',' )
filterGrid ( query )
document . querySelector ( '#applied-filters' ). textContent = " giving " + IsotopeGrid . getFilteredItemElements (). length + " results"
})
Except as otherwise noted, the content of this page is licensed under the Creative Commons Attribution 4.0 License , and code samples are licensed under the Apache 2.0 License . For details, see the Google Developers Site Policies . Java is a registered trademark of Oracle and/or its affiliates.
Last updated 2023-07-05 UTC.
[[["Easy to understand","easyToUnderstand","thumb-up"],["Solved my problem","solvedMyProblem","thumb-up"],["Other","otherUp","thumb-up"]],[["Missing the information I need","missingTheInformationINeed","thumb-down"],["Too complicated / too many steps","tooComplicatedTooManySteps","thumb-down"],["Out of date","outOfDate","thumb-down"],["Samples / code issue","samplesCodeIssue","thumb-down"],["Other","otherDown","thumb-down"]],["Last updated 2023-07-05 UTC."],[],[]]