NoLoJS logo

Filter - Buttons & Categories

A CSS-only content filter, making the filters look more like buttons, and showing based on “categories”.

Demo

Filter
  • Angular

    angularjs

    This card has both "angular" and "js" CSS classes, so once you have interacted with the filter, it should be visible if "Angular" and/or "JS" is checked.

  • CSS

    css

    This card only has a "css" class, so once you have interacted with the filter, it should only be visible if "CSS" is checked.

  • HTML

    html

    This card only has a "html" class, so once you have interacted with the filter, it should only be visible if "HTML" is checked.

  • JS

    js

    This card only has a "js" class, so once you have interacted with the filter, it should only be visible if "JS" is checked.

  • PHP

    php

    This card only has a "php" class, so once you have interacted with the filter, it should only be visible if "PHP" is checked.

  • Python

    python

    This card only has a "python" class, so once you have interacted with the filter, it should only be visible if "Python" is checked.

  • React

    reactjs

    This card has both "react" and "js" CSS classes, so once you have interacted with the filter, it should be visible if "React" and/or "JS" is checked.

  • SCSS

    scsscss

    This card has both "scss" and "css" CSS classes, so once you have interacted with the filter, it should be visible if "SCSS" and/or "CSS" is checked.

  • Svelte

    sveltejs

    This card has both "svelte" and "js" CSS classes, so once you have interacted with the filter, it should be visible if "Svelte" and/or "JS" is checked.

  • Tailwind

    tailwindcss

    This card has both "tailwind" and "css" CSS classes, so once you have interacted with the filter, it should be visible if "Tailwind" and/or "CSS" is checked.

HTML

<!-- List of labels and checkboxes for each filter option; note the `name` attribute here matches the `data-category` below -->
<fieldset>
  <legend>Filter</legend>
  <ul>
    <li>
      <input id="angular" name="angular" type="checkbox">
      <label for="angular">Angular</label>
    </li>
    <li>
      <input id="css" name="css" type="checkbox">
      <label for="css">CSS</label>
    </li>
    <li>
      <input id="html" name="html" type="checkbox">
      <label for="html">HTML</label>
    </li>
    <li>
      <input id="js" name="js" type="checkbox">
      <label for="js">JS</label>
    </li>
    <li>
      <input id="php" name="php" type="checkbox">
      <label for="php">PHP</label>
    </li>
    <li>
      <input id="python" name="python" type="checkbox">
      <label for="python">Python</label>
    </li>
    <li>
      <input id="react" name="react" type="checkbox">
      <label for="react">React</label>
    </li>
    <li>
      <input id="scss" name="scss" type="checkbox">
      <label for="scss">SCSS</label>
    </li>
    <li>
      <input id="svelte" name="svelte" type="checkbox">
      <label for="svelte">Svelte</label>
    </li>
    <li>
      <input id="tailwind" name="tailwind" type="checkbox">
      <label for="tailwind">Tailwind</label>
    </li>
   </ul> 
</fieldset>

<!-- Content that will be filtered; note the `data-category` here matches the `name` attribute above -->
<section>
  <ul>
    <li>
      <h3>Angular</h3>
      <span data-category="angular">angular</span><span data-category="js">js</span>
      <p>This card has both "angular" and "js" CSS classes, so once you have interacted with the filter, it should be visible if "Angular" <em>and/or</em> "JS" is checked.</p>
    </li>
    <li>
      <h3>CSS</h3>
      <span data-category="css">css</span>
      <p>This card only has a "css" class, so once you have interacted with the filter, it should <em>only</em> be visible if "CSS" is checked.</p>
    </li>
    <li>
      <h3>HTML</h3>
      <span data-category="html">html</span>
      <p>This card only has a "html" class, so once you have interacted with the filter, it should <em>only</em> be visible if "HTML" is checked.</p>
    </li>
    <li>
      <h3>JS</h3>
      <span data-category="js">js</span>
      <p>This card only has a "js" class, so once you have interacted with the filter, it should <em>only</em> be visible if "JS" is checked.</p>
    </li>
    <li>
      <h3>PHP</h3>
      <span data-category="php">php</span>
      <p>This card only has a "php" class, so once you have interacted with the filter, it should <em>only</em> be visible if "PHP" is checked.</p>
    </li>
    <li>
      <h3>Python</h3>
      <span data-category="python">python</span>
      <p>This card only has a "python" class, so once you have interacted with the filter, it should <em>only</em> be visible if "Python" is checked.</p>
    </li>
    <li>
      <h3>React</h3>
      <span data-category="react">react</span><span data-category="js">js</span>
      <p>This card has both "react" and "js" CSS classes, so once you have interacted with the filter, it should be visible if "React" <em>and/or</em> "JS" is checked.</p>
    </li>
    <li>
      <h3>SCSS</h3>
      <span data-category="scss">scss</span><span data-category="css">css</span>
      <p>This card has both "scss" and "css" CSS classes, so once you have interacted with the filter, it should be visible if "SCSS" <em>and/or</em> "CSS" is checked.</p>
    </li>
    <li>
      <h3>Svelte</h3>
      <span data-category="svelte">svelte</span><span data-category="js">js</span>
      <p>This card has both "svelte" and "js" CSS classes, so once you have interacted with the filter, it should be visible if "Svelte" <em>and/or</em> "JS" is checked.</p>
    </li>
    <li>
      <h3>Tailwind</h3>
      <span data-category="tailwind">tailwind</span><span data-category="css">css</span>
      <p>This card has both "tailwind" and "css" CSS classes, so once you have interacted with the filter, it should be visible if "Tailwind" <em>and/or</em> "CSS" is checked.</p>
    </li>
  </ul>
</section>

CSS

/* Confine scope to the demo only */
.demo {
  /* Hide all LIs if any LI is checked... */
  :has(:checked) section li {
    display: none;
  }
  /* then display only those that are checked */
  :has([name="angular"]:checked) li:has([data-category="angular"]),
  :has([name="css"]:checked) li:has([data-category="css"]),
  :has([name="html"]:checked) li:has([data-category="html"]),
  :has([name="js"]:checked) li:has([data-category="js"]),
  :has([name="php"]:checked) li:has([data-category="php"]),
  :has([name="python"]:checked) li:has([data-category="python"]),
  :has([name="react"]:checked) li:has([data-category="react"]),
  :has([name="scss"]:checked) li:has([data-category="scss"]),
  :has([name="svelte"]:checked) li:has([data-category="svelte"]),
  :has([name="tailwind"]:checked) li:has([data-category="tailwind"]) {
    display: list-item;
  }
  
  /* Only for comsetics */
  :root {
    --green-dark: #34a0a4;
    --green-med: #a1c9c9;
    --green-light: #f6f7f1;
  }
  body {
    margin: 0;
    background-color: var(--green-light);
    font-family: sans-serif;
    font-size: 16px;
    line-height: 1.2;
    padding: 1rem;
    padding-block-end: 100rem;
  }
  hr {
    margin-block: 2em;
  }
  fieldset {
    background-color: var(--green-med);
    border: 1px solid var(--green-dark);
    ul {
      display: flex;
      flex-wrap: wrap;
      gap: 1rem;
    }
    li {
      position: relative;
    }
    label {
      position: relative;
      padding-block: 2px;
      padding-inline: 8px;
      background-color: var(--green-light);
      border: 1px solid var(--green-dark);
    }
    input {
      position: absolute;
    }
    /* If any filter is checked, erduce opacity for all...*/
    :has(:checked) li {
      opacity: .25;
    }
    /* ... then restore opacity for whatever IS checked. */
    :has(:checked) li:has(:checked) {
      opacity: 1;
    }
  }
  legend {
    padding-block: 2px;
    padding-inline: 8px;
    background-color: var(--green-light);
    border: 1px solid var(--green-dark);
  }
  ul {
    list-style: none;
    padding: 0;
    display: grid;
  }
  
  section {
    ul {
      grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
      gap: 1rem;
    }
    li {
      flex: 1 1 200px;
      padding-block: 2px;
      padding-inline: 8px;
      background-color: var(--green-med);
      border: 1px solid var(--green-dark);
    }
    span {
      margin: 2px;
      padding: 2px 4px;
      background-color: var(--green-light);
      border: 1px solid var(--green-dark);
      border-radius: 4px;
      font-size: .8rem;
    }
  }
}

JS

No JS required.

Baseline

[`has`](https://webstatus.dev/features/has)

CodePen

See the Pen on CodePen.