Creare un componente a selezione multipla

Una panoramica di base su come creare un componente reattivo, adattivo, accessibile e a selezione multipla per ordinare e filtrare le esperienze utente.

In questo post voglio condividere le idee su come creare un componente a selezione multipla. Prova la demo.

Demo

Se preferisci i video, ecco una versione di questo post su YouTube:

Panoramica

Agli utenti vengono spesso presentati alcuni elementi, a volte molti, e in queste casi, potrebbe essere una buona idea fornire un modo per ridurre l'elenco per evitare sovraccarico di scelta. Questo post del blog esplora l'applicazione di filtri all'interfaccia utente per ridurre le scelte. Per farlo, presentando attributi degli articoli che gli utenti possono selezionare o deselezionare, riducendo i risultati riducendo il sovraccarico di opzioni.

Interazioni

L'obiettivo è consentire il trasferimento rapido delle opzioni di filtro per tutti gli utenti e i loro tipi di input diversi. con una presentazione adattabile e adattabile coppia di componenti. Una tradizionale barra laterale di caselle di controllo per desktop, tastiera e screen reader, oltre a una <select multiple> per gli utenti touch.

Screenshot di confronto che mostra desktop chiaro e scuro con una barra laterale
caselle di controllo rispetto ai dispositivi mobili iOS e Android con un elemento a selezione multipla.

La decisione di utilizzare la selezione multipla integrata per il tocco e non per il desktop consente di risparmiare lavoro e crea lavoro, ma credo che offra esperienze appropriate con un debito di codice inferiore rispetto a creare l'intera esperienza reattiva in un solo componente.

Tocco

Il componente touch consente di risparmiare spazio e aiuta l'utente a interagire con la massima precisione mobile. Consente di risparmiare spazio comprimendo un'intera barra laterale di caselle di controllo Esperienza touch overlay integrata di <select>. Migliora la precisione dell'input mostrando un ampio overlay touch fornito dal sistema.

R
anteprima screenshot dell&#39;elemento con selezione multipla in Chrome su Android, iPhone e
iPad. L&#39;iPad e l&#39;iPhone hanno la selezione multipla attivata e ognuno ottiene
un&#39;esperienza unica ottimizzata per le dimensioni dello schermo.

Tastiera e gamepad

Di seguito è riportata una dimostrazione di come utilizzare <select multiple> dalla tastiera.

Questa selezione multipla integrata non può essere adattata allo stile ed è offerta solo in una versione compatta non adatto a presentare molte opzioni. Scopri come non è possibile vedere l'ampia gamma di opzioni in quella piccola casella? Anche se puoi modificarne le dimensioni, ancora non utilizzabili come barre laterali di caselle di controllo.

Aumento

Entrambi i componenti saranno contenuti nello stesso elemento <form>. I risultati di questo modulo, che si tratti di caselle di controllo o selezione multipla, verrà osservato e utilizzato per filtrare la griglia, ma potrebbero anche essere inviate a un server.

<form>

</form>

Componente Caselle di controllo

I gruppi di caselle di controllo devono essere racchiusi in una <fieldset> e viene fornito un <legend>. Quando l'HTML è strutturato in questo modo, gli screen reader e FormData a comprendere automaticamente la relazione degli elementi.

<form>
  <fieldset>
    <legend>New</legend>
    … checkboxes …
  </fieldset>
</form>

Con il raggruppamento attivo, aggiungi <label> e <input type="checkbox"> per per ciascuno dei filtri. Ho scelto di aggregare il mio file in <div>, quindi la proprietà gap del CSS possono distribuirle uniformemente e mantenere l'allineamento quando le etichette sono su più righe.

<form>
  <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>
</form>

Uno screenshot con un overlay informativo per la legenda e
  set di campi, mostra il colore e il nome dell&#39;elemento.

<select multiple> componente

Una funzionalità raramente utilizzata dell'elemento <select> è multiple Quando l'attributo viene utilizzato con un elemento <select>, l'utente può: e sceglierli dall'elenco. È come modificare l'interazione da un elenco di segnali radio a un elenco di caselle di controllo.

<form>
  <select multiple="true" title="Filter results by category">
    …
  </select>
</form>

Per etichettare e creare gruppi all'interno di un <select>, utilizza le <optgroup> e assegnargli un attributo e un valore label. Questo elemento e questo attributo sono simili agli elementi <fieldset> e <legend>.

<form>
  <select multiple="true" title="Filter results by category">
    <optgroup label="New">
      …
    </optgroup>
  </select>
</form>

Ora aggiungi il <option> per il filtro.

<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>
  </select>
</form>

Uno screenshot del rendering desktop di un elemento a selezione multipla.

Monitoraggio degli input con i contatori per informare sulle tecnologie per la disabilità

Lo stato ruolo tecnica utilizzata in questa esperienza utente, per monitorare e mantenere filtri per screen reader e altre tecnologie per la disabilità. Il video di YouTube illustra la caratteristica. L'integrazione inizia con il codice HTML e l'attributo role="status".

<div role="status" class="sr-only" id="applied-filters"></div>

Questo elemento leggerà ad alta voce le modifiche apportate ai contenuti. Possiamo aggiornare contenuti con CSS contatori man mano che gli utenti interagiscono con le caselle di controllo. Per farlo dobbiamo prima creare un contatore con un nome su un elemento principale degli input e dell'elemento di stato.

aside {
  counter-reset: filters;
}

Per impostazione predefinita, il conteggio sarà 0, il che è ottimo, niente è :checked per per impostazione predefinita.

Successivamente, per aumentare il contatore appena creato, sceglieremo come target gli elementi secondari dei Elemento <aside> che corrisponde a :checked. Quando l'utente cambia lo stato degli input, il contatore filters verrà conteggiato.

aside :checked {
  counter-increment: filters;
}

Ora CSS è a conoscenza del conteggio generale dell'interfaccia utente della casella di controllo e del ruolo dello stato è vuoto e in attesa di valori. Dal momento che il CSS mantiene il punteggio in la memoria, counter() consente di accedere al valore da pseudo Element:

aside #applied-filters::before {
  content: counter(filters) " filters ";
}

L'HTML per l'elemento status role annuncerà "2 filtri" a una schermata Reader. È un buon inizio, ma possiamo fare di meglio, ad esempio condividiamo il conteggio risultati aggiornati dei filtri. Lo faremo da JavaScript, poiché al di fuori di ciò che possono fare i contatori.

Uno screenshot dello screen reader di MacOS che annuncia il numero di filtri attivi.

Emozioni per nidificare

L'algoritmo dei contatori ha trovato molto interessanti con CSS nesting-1, dato che ho potuto inserire tutti la logica in un blocco. Per la lettura e l'aggiornamento è portatile e centralizzato.

aside {
  counter-reset: filters;

  & :checked {
    counter-increment: filters;
  }

  & #applied-filters::before {
    content: counter(filters) " filters ";
  }
}

Layout

Questa sezione descrive i layout tra i due componenti. La maggior parte gli stili di layout sono destinati al componente casella di controllo desktop.

Il modulo

Per ottimizzare la leggibilità e la leggibilità per gli utenti, al modulo viene assegnato un massimo di 30 caratteri, impostando essenzialmente una larghezza ottica delle linee sull'etichetta del filtro. Il modulo utilizza il layout a griglia e la proprietà gap per distribuire la set di campi.

form {
  display: grid;
  gap: 2ch;
  max-inline-size: 30ch;
}

Elemento <select>

L'elenco di etichette e caselle di controllo occupano troppo spazio sui dispositivi mobili. Di conseguenza, il layout verifica che il dispositivo di puntamento principale dell'utente venga modificato per l'esperienza touch.

@media (pointer: coarse) {
  select[multiple] {
    display: block;
  }
}

Il valore coarse indica che l'utente non potrà interagire con schermo con un'elevata precisione con il dispositivo di input principale. Su un dispositivo mobile, il valore del puntatore è spesso coarse, come interazione principale è tocco. Su un computer, il valore del puntatore è spesso fine in quanto è comune di avere collegato un mouse o un altro dispositivo di input ad alta precisione.

I set di campi

Lo stile e il layout predefiniti di <fieldset> con <legend> sono univoci:

Uno screenshot degli stili predefiniti per un set di campi e una legenda.

Normalmente, per distribuire gli elementi secondari utilizzerei la proprietà gap, ma l'attributo la posizione dell'elemento <legend> rende difficile la creazione di un set a spaziatura uniforme dei bambini. Invece di gap, l'elemento di pari livello adiacente selettore e margin-block-start.

fieldset {
  padding: 2ch;

  & > div + div {
    margin-block-start: 2ch;
  }
}

In questo modo, <legend> non può modificare lo spazio utilizzando come target solo <div> minori.

Screenshot che mostra la spaziatura dei margini tra gli input, ma non la legenda.

L'etichetta del filtro e la casella di controllo

Come elemento secondario diretto di un <fieldset> e entro la larghezza massima del valore 30ch, il testo dell'etichetta potrebbe andare a capo se troppo lungo. La disposizione del testo a capo va bene, il disallineamento tra testo e casella di controllo non lo è. Flexbox è l'ideale.

fieldset > div {
  display: flex;
  gap: 2ch;
  align-items: baseline;
}
Screenshot che mostra come il segno di spunta si allinea a
    la prima riga di testo in uno scenario di wrapping di più righe.
Riproduci di più in questo Codepen

La griglia animata

L'animazione del layout è eseguita da Isotope. R dalle prestazioni elevate per l'ordinamento e il filtro interattivi.

JavaScript

Oltre ad aiutare a orchestrare una griglia animata e interattiva, in tempo reale viene usato per lucidare un paio di bordi grezzi.

Normalizzare l'input utente

Questo design ha un unico modulo con due diversi modi per fornire input. non devi serie il modello in modo analogo. Con un po' di codice JavaScript, però, normalizzare i dati.

Screenshot della console JavaScript DevTools che
  mostra l&#39;obiettivo, i risultati dei dati normalizzati.

Ho scelto di allineare la struttura dei dati dell'elemento <select> alle caselle di controllo raggruppate alla struttura del centro di costo. Per fare ciò, input all'elemento <select> viene aggiunto un listener di eventi, dopodiché viene selectedOptions vengono mappati.

document.querySelector('select').addEventListener('input', event => {
  // make selectedOptions iterable then reduce a new array object
  let selectData = Array.from(event.target.selectedOptions).reduce((data, opt) => {
    // parent optgroup label and option value are added to the reduce aggregator
    data.push([opt.parentElement.label.toLowerCase(), opt.value])
    return data
  }, [])
})

Ora puoi inviare il modulo in sicurezza oppure, nel caso di questa demo, dare istruzioni a Isotope in base ai quali filtrare.

Completamento dell'elemento "Status Role" in corso...

L'elemento conteggia e annuncia il conteggio dei filtri solo in base alla casella di controllo interazione, ma ho trovato una buona idea condividere anche il numero di e garantire che vengano conteggiate anche le scelte dell'elemento <select>.

La scelta dell'elemento <select> si riflette in counter()

Nella sezione di normalizzazione dei dati, è già stato creato un listener nell'input. Alle ore alla fine di questa funzione il numero di filtri scelti e il numero di risultati per questi filtri sono noti. I valori possono essere passati all'elemento "State Role" in questo modo.

let statusRoleElement = document.querySelector('#applied-filters')
statusRoleElement.style.counterSet = selectData.length

Risultati riportati nell'elemento role="status"

:checked offre un modo integrato per passare il numero di filtri scelti a l'elemento status role, ma manca di visibilità per il numero di risultati filtrati. JavaScript può rilevare l'interazione con le caselle di controllo e, dopo aver applicato un filtro al griglia, aggiungi textContent come ha fatto l'elemento <select>.

document
  .querySelector('aside form')
  .addEventListener('input', e => {
    // isotope demo code
    let filterResults = IsotopeGrid.getFilteredItemElements().length
    document.querySelector('#applied-filters').textContent = `giving ${filterResults} results`
})

Nel complesso questo lavoro completa l'annuncio "2 filtri che danno 25 risultati".

Uno screenshot dello screen reader di MacOS che annuncia i risultati.

Ora la nostra eccellente esperienza relativa alle tecnologie per la disabilità sarà disponibile per tutti ma gli utenti vi interagiscono.

Conclusione

Ora che sai come ci ho fatto, come faresti‽ 🙂

Diversificaamo i nostri approcci e impariamo tutti i modi per creare sul web. Crea una demo, twittami con i link e la aggiungerò alla sezione dei remix della community qui sotto.

Remix della community

Ancora niente da visualizzare qui.