@mootari/mutable-forms and buttons as multi-value text/color toggles ?

I apologize in advance that this question isn’t associated with a notebook. While I’ve hacked around drawing from myriad internet examples, I still haven’t gotten to a happy place…

I’d like to create a button input for which both text and color changes on click, and clicks cycle through a few options. I’ve gotten this sort of thing working well for binary values, but haven’t managed to get color and text changes to line up for multiple values. For example, one button would cycle through three options:

select - grey
yes - red
no - green

I see that the ‘test passed’ / ‘test failed’ indicators in @mootari/mutable-forms adjust colors when values match parameters using a style.color = match ?

Before I starting hacking around with this notebook, I was hoping someone would tell me whether or not it’d be a relatively useful exercise.

Thanks in advance!

Wild… and clearly I have no idea what I’m doing…

Sure, I think it’d be useful! Certainly it’s a great learning exercise and it’s always good to have more importable inputs available!

One way to deal with more than two options is to store the possible states in an array and have an index that keeps track of the current state which cycles through 0, … , number of states using the % operator: see e.g. how I handle the options in the gridClick functions in my Grid inputs notebook for an example.

I see you’ve just posted an attempt. Here’s a little advice: it should be possible to do this in a single cell without having to use mutable cells. You might try filling in this skeleton:

viewof button = {
  const form = html`<form><button name=button>Init`;
  const states = [{}, {}, {}]; // <-- fill in data for the three state objects 
  let currentIndex = 0; // this variable keeps track of the state the form is in. It should cycle through 0, 1, 2 when the button is clicked
  form.button.onclick = event => {
    // <-- insert logic to cycle through currentIndex here
    // <-- update the value of the form using states[currentIndex]
    // <-- change button styling / text using states[currentIndex]
    event.preventDefault(); // Don’t submit the form.
    form.dispatchEvent(new CustomEvent("input"));
  };
  form.value = states[0]; // <-- set the initial value of this input (depending on the structure of the state objects, you might want this to use just a specific field e.g. states[0].value)
  return form;
}
1 Like

Nice! Thanks @bgchen! I’ll work on the logic bits within this skeleton and see if I can figure my way through to a functional implementation.

I’d normally use a select dropdown or radio buttons for this, but here you go:

2 Likes

Thanks @mbostock! I see that you associate a color value to each of the button labels. I’ll see if I can’t find a way to have these values affect the color of the button itself.

form.button.backgroundColor=state.value; not effecting change in button color
form.style.backgroundColor=state.value; effects change, but not to the button itself

… more soon.

Just for completeness’ sake, you can also cycle the inputs themselves: I. e., create distinct buttons each with their own handler and cycle them by attaching / detaching.

1 Like

Try form.button.style.backgroundColor.

1 Like

Awesome! Thank you!

Thanks to everyone: @bgchen, @mbostock, @mootari ! I appreciate your help with this. To bring this to a close, I’ve published a notebook:

1 Like

I believe that tri-state / indeterminate checkboxes might have acted as inspiration (@aaronkyle correct me if I’m wrong). Some examples:

Nice references, @mootari ! I was indeed looking for something like this. :slight_smile:

Nice, Aaron! For practice, I made a variation which allows you to delete / reorder / insert new items (feel free to merge if you think it’s useful):

This is the first approach that popped into my head: I’d definitely be curious to see if there are cleaner methods.

Very cool! I’ve merged in your enhancements and added some shout-outs for all these amazing contributions. Thank you!

1 Like