Skip to content

GoBoldlyForward/rankchoice

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

rankchoice

Drop-in replacement for <select multiple> that captures both the chosen values and the position the user puts them in. Tap to add, drag to reorder — the form posts an ordered array, no submit handler needed.

Demo

goboldlyforward.github.io/rankchoice — tap to add, drag the ranked items to reorder, submit to see what the server would receive.

What it does

  • Auto-mounts on any <select multiple data-rankchoice>. Hides the native control and renders a tap-to-pick / drag-to-reorder UI in its place.
  • Each pick rises to the top of the ranked list and is numbered in the order chosen.
  • Writes a set of ordered hidden <input name="<name>[]"> fields so the form posts an array — Rails reads params[:favorites] as ["tacos", "pizza"], position is the array index.
  • Original <option selected> attributes are kept in sync on every change (in option order — native HTML has no concept of selection order), so server-side fallback still works if your backend doesn't use the [] form.
  • Progressive enhancement: if JavaScript fails to load, the native multi-select still works (just without ordering).
  • Optional per-option emoji via data-emoji.

No framework, no build step. Drop in the CSS + JS and add an attribute.

Install

npm install @goboldlyforward/rankchoice

Or grab the files directly:

<link rel="stylesheet" href="path/to/rankchoice.css">
<script src="path/to/rankchoice.js"></script>

Usage

<form action="/preferences" method="post">
  <select multiple data-rankchoice name="favorites">
    <option value="pizza" data-emoji="🍕">Pizza</option>
    <option value="tacos" data-emoji="🌮">Tacos</option>
    <option value="sushi" data-emoji="🍣">Sushi</option>
  </select>
  <button>Save</button>
</form>

The plugin auto-inits on DOMContentLoaded.

Markup

Attribute On What it does
data-rankchoice <select> Required. Marks the element for auto-init.
name <select> Required. Used for the hidden name[] inputs.
data-value <select> Comma-separated ids in position order. Overrides per-option selected.
data-label <select> Accessible label for the widget.
data-emoji <option> Emoji shown alongside the label.

API

// Manual init (after injecting new selects)
RankChoice.initAll(scope);          // scan a subtree for [data-rankchoice]
RankChoice.init(selectElement);     // mount one

// Get the live instance
const inst = RankChoice.instances.get(selectElement);
inst.getValue();                    // ["tacos", "pizza"]
inst.setValue(["sushi", "pizza"]);  // replace selection (animated)
inst.destroy();                     // restore the original <select>

Events

Both fire on the original <select> and bubble:

selectElement.addEventListener("change", (e) => {
  // native-style; query the select or instance for the value
});
selectElement.addEventListener("rankchoice:change", (e) => {
  console.log(e.detail.value);      // ["tacos", "pizza"]
});

Requirements

HTML, CSS, and ~20KB of JavaScript. No framework, no build step. Native HTML5 drag-and-drop.

License

MIT — see LICENSE.

About

Drop-in replacement for select multiple that captures both the chosen values and the position the user puts them in. Tap to add, drag to reorder — the form posts an ordered array.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors