Input type="radio" is not working as expected

I am trying to create a radio group and since it spans over several line, with images in between I cannot use sp-radio-group. I tried and it did not work.

I am using:

<div id="presets_split" class="presetImg_split hCenter">
      <div>
        <img id="selS_row1_split" src="./images/splitsS1x6.png">
      </div>
      <div class="presetLine_split">
          <input type="radio" class="preset_radio_split" value="A" name="whichPreset"></input>
          <input type="radio" class="preset_radio_split" value="B" name="whichPreset"></input>
          <input type="radio" class="preset_radio_split" value="C" name="whichPreset"></input>
          <input type="radio" class="preset_radio_split" value="D" name="whichPreset"></input>
          <input type="radio" class="preset_radio_split" value="E" name="whichPreset"></input>
          <input type="radio" class="preset_radio_split" value="F" name="whichPreset"></input>
      </div>

      <div>
        <img id="selS_row1_split" src="./images/splitsS2x6.png">
      </div>
      <div class="presetLine_split">
          <input type="radio" class="preset_radio_split" value="A" name="whichPreset"></input>
          <input type="radio" class="preset_radio_split" value="B" name="whichPreset"></input>
          <input type="radio" class="preset_radio_split" value="C" name="whichPreset"></input>
          <input type="radio" class="preset_radio_split" value="D" name="whichPreset"></input>
          <input type="radio" class="preset_radio_split" value="E" name="whichPreset"></input>
          <input type="radio" class="preset_radio_split" value="F" name="whichPreset"></input>
      </div>
    </div>

to generate this:

I add the name= attribute to link all groups together.
I do not want to use to onclick event, I will check this when submitting the form.
The problem is that:

  1. the selected item, if it is selected at all, shows fait blue circle and
  2. It gets deselected as soon as i press any other button or the panel loose focus.

What is wrong with it?
Can I use sp-radio-group across multiple divs?

I tried the “kitchen sink” and it appears you can’t press the native radio buttons in it either.

I managed to do something you wanted to achieve. I did it in React but you will get the point. Maybe you can use the SVG icons, and with some CSS tricks like in this code, I did you will get what you need. As far as I know, the recommendation is to use sp- components instead of native web elements as these are going to be deprecated in the future.

import { useState } from "react";

const svgIcon = (
  <svg
    xmlns="http://www.w3.org/2000/svg"
    viewBox="0 0 512 512"
    style={{
      width: "20px",
      height: "20px",
      position: "relative",
      top: "-60px",
      left: "-2px",
      fill: "white",
    }}
  >
    <path d="M256 32V51.2C329 66.03 384 130.6 384 208V226.8C384 273.9 401.3 319.2 432.5 354.4L439.9 362.7C448.3 372.2 450.4 385.6 445.2 397.1C440 408.6 428.6 416 416 416H32C19.4 416 7.971 408.6 2.809 397.1C-2.353 385.6-.2883 372.2 8.084 362.7L15.5 354.4C46.74 319.2 64 273.9 64 226.8V208C64 130.6 118.1 66.03 192 51.2V32C192 14.33 206.3 0 224 0C241.7 0 256 14.33 256 32H256zM224 512C207 512 190.7 505.3 178.7 493.3C166.7 481.3 160 464.1 160 448H288C288 464.1 281.3 481.3 269.3 493.3C257.3 505.3 240.1 512 224 512z" />{" "}
  </svg>
);

const options = [
  { value: 1, icon: svgIcon },
  { value: 2, icon: svgIcon },
  { value: 3, icon: svgIcon },
  { value: 4, icon: svgIcon },
  { value: 5, icon: svgIcon },
  { value: 6, icon: svgIcon },
];

const RadioButtons = () => {
  const [selectedOption, setSelectedOption] = useState(options[0].value);

  return (
    <div
      style={{
        display: "flex",
        marginTop: "35px",
        marginLeft: "30px",
      }}
    >
      <sp-radio-group name="example">
        {options.map((option) => (
          <sp-radio
            value={option.value}
            style={{
              margin: "20px",
              display: "block",
              position: "relative",
            }}
            checked={option.value === selectedOption ? true : undefined}
            onClick={() => setSelectedOption(option.value)}
            key={option.value.toString()}
          >
            {option.icon}
          </sp-radio>
        ))}
      </sp-radio-group>
    </div>
  );
};

export default RadioButtons;


I decided, until adobe fix this, to wrap the radio button in ab , add some css and it is working. I need to remember to press a little bit outside the button though.

  <div class="presetLine_split">
        <a id="preset_H7" class="link"><input type="radio" class="preset_radio_split" value="H7" name="which_H"></input></a>
        <a id="preset_H8" class="link"><input type="radio" class="preset_radio_split" value="H8" name="which_H"></input></a>
        <a id="preset_H9" class="link"><input type="radio" class="preset_radio_split" value="H9" name="which_H"></input></a>
        <a id="preset_H10" class="link"><input type="radio" class="preset_radio_split" value="H10" name="which_H"></input></a>
        <a id="preset_H11" class="link"><input type="radio" class="preset_radio_split" value="H11" name="which_H"></input></a>
        <a id="preset_H12" class="link"><input type="radio" class="preset_radio_split" value="H12" name="which_H"></input></a>
      </div>
  • js:
var whichPreset = ["V", "H"];
for (i = 0; i < whichPreset.length; i++) {
    for (j = 1; j <= 12; j++) {
        const id = "preset_" + whichPreset[i] + j;
        $("#" + id).click(function () {
            document.getElementById(id).childNodes[0].checked = true;
            panelDataSplit.selectedPreset = document.getElementById(id).childNodes[0].value;
            console.log("Preset: " + panelDataSplit.selectedPreset);
        });
    }
}

If you use the code that I sent you you could click on the image (SVG code) or the radio button (the small circle) and it would activate the selected option. As I saw when I used that kitchen sink sample code, the behavior of the sp-radio-button is better than the native HTML element. You don’t need to be so precise with the mouse in order to select the radio button you want.

Thanks, I’ll give it a go.
How would you convert this React to non React?
Can you show a basic example for that.
html, js & css?

Sure. I didn’t test this on Photoshop but it could be like the following:

HTML

<html>
  <head>
    <title>My app</title>
    <meta charset="UTF-8" />
    <script src="src/index.js" defer></script>
  </head>

  <body>
    <div id="app">
      <sp-radio-group class="radio-buttons" name="radioExample"></sp-radio-group>
    </div>
  </body>
</html>

CSS

.radio-buttons {
  display: flex;
}

.radio-button {
  margin: 20px;
  display: block;
  position: relative;
}

.svg-icon {
  width: 20px;
  height: 20px;
  position: relative;
  top: -60px;
  left: -2px;
  fill: white;
}

JS

import "./styles.css";

const svgIcon = `<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 512 512" class="svg-icon"
>
<path d="M256 32V51.2C329 66.03 384 130.6 384 208V226.8C384 273.9 401.3 319.2 432.5 354.4L439.9 362.7C448.3 372.2 450.4 385.6 445.2 397.1C440 408.6 428.6 416 416 416H32C19.4 416 7.971 408.6 2.809 397.1C-2.353 385.6-.2883 372.2 8.084 362.7L15.5 354.4C46.74 319.2 64 273.9 64 226.8V208C64 130.6 118.1 66.03 192 51.2V32C192 14.33 206.3 0 224 0C241.7 0 256 14.33 256 32H256zM224 512C207 512 190.7 505.3 178.7 493.3C166.7 481.3 160 464.1 160 448H288C288 464.1 281.3 481.3 269.3 493.3C257.3 505.3 240.1 512 224 512z" />{" "}
</svg>`;

const options = [
  { value: 1, icon: svgIcon },
  { value: 2, icon: svgIcon },
  { value: 3, icon: svgIcon },
  { value: 4, icon: svgIcon },
  { value: 5, icon: svgIcon },
  { value: 6, icon: svgIcon }
];

// Map all options into separate sp-radio components
document.querySelector(".radio-buttons").innerHTML = `${options
  .map(
    (option) =>
      `<sp-radio class="radio-button" value=${option.value}>${option.icon}</sp-radio>`
  )
  .join("")}`;

// Add event listener for a checked option
document
  .querySelector(".radio-buttons")
  .addEventListener("change", (e) =>
    console.log(`Selected item: ${e.target.value}`)
  );

Thanks, I’ll try it later on

After looking at your modified CSS, I made a few changes to the margins and add my original image:

.radio-buttons {
  display: flex;
  margin-left: 25px;
  margin-right: 15px;
}

.radio-button {
  margin-left: 8px;
  margin-right: 17px;
  display: block;
  position: relative;
}

Do you know how to get the selected radio value? I don’t want to use an event listener - I want to check the value before sending.
I used to do:
$('input[name=which_V]:checked', '#preset_V').val();
I could iterate over all the radio buttons but is there a more elegant way with sp-radio-group?

The most elegant solution is to add a single event listener to the sp-radio-group and then listen to a “change” event. Because that group has a “name” property and only a single radio button can be selected at a time it will give you only the selected option.

function getSelectedRadio(groupId, groupName) {
  group = $('[name=' + groupName + ']', '#' + groupId);
  for (var i = 0; i < group.length; i++) {
    if (group[i].checked) {
      return group[i].value;
    }
  }
  return false;
}

groupId can be skipped for most radio buttons.

Well, you can do a for loop if you want to. I think it’s less code and more elegant to have one event listener that is added just for an sp-radio-group element like this:

// Add event listener for a checked option
document
  .querySelector(".radio-buttons")
  .addEventListener("change", (e) =>
    console.log(`Selected item: ${e.target.value}`)
  );

That class name radio-buttons is the class for the sp-radio-group element. But you can do a for loop if you prefer it as long as it works :slight_smile:

And it’s important to use and set that name attribute for the sp-radio-group element so that all radio buttons are grouped under the same name and only a single radio button can be selected at the time.

I will, however, it is working without the name in the group.
I think the name is not supported (remember reading abut it in one of the question in this forum).
I thing everything in a group is under the same name

Yes. I saw they didn’t list it on the official UXP documentation but at the same time, it can be found in the “kitchen sink” sample code.
I guess it won’t hurt to have it but it can work without it as well. That event listener can be attached to an element with that specific class name (like in this example .radio-buttons) and it should work on “change” event like they showed it on the official documentation:

https://developer.adobe.com/photoshop/uxp/uxp/reference-spectrum/User%20Interface/sp-radio-group/#responding-to-events