4

How can I use radio inputs instead of checkboxes for a selectable table in React Table?

There is an example for checkboxes but not radio buttons: https://github.com/tannerlinsley/react-table/blob/master/examples/row-selection/src/App.js

Changing the IndeterminateCheckox to use a radio input doesn't work as the selection state is not updated in React Table:

const IndeterminateCheckbox = React.forwardRef(({ indeterminate, ...rest }, ref) => {
    const defaultRef = React.useRef();
    const resolvedRef = ref || defaultRef;

    useEffect(() => {
      resolvedRef.current.indeterminate = indeterminate;
    }, [resolvedRef, indeterminate]);

    return <input name="select-radio" type="radio" ref={resolvedRef} {...rest} />
    );
  });


It looks correct but does not pass the correct selection state back:
enter image description here

Alex
  • 2,651
  • 2
  • 25
  • 45
  • What happens when you select different options? Do you see any changes to the component / component state in your dev tools? Also, what's included in `...rest` -- does it include everything you expect? It seems most likely that your table implementation is fine and the bug is in your state implementation. – the holla Apr 02 '20 at 21:29
  • If you take a closer look at the useRowSelect example React Table stores a 'selected' state for the row which was clicked. It assumes the use of checkboxes so it allows for multiple selections to be passed down through ...rest. I think the easiest solution to this would be to implement custom radio inputs inside a data cell rather than using useRowSelect, I just thought someone else would have run into this before. – Alex Apr 03 '20 at 12:32

3 Answers3

3

Had a quick look. Try this:

  • Have a state for the rowId
const [selectedRowId, setSelectedRowId] = useState(null);
  • Pass autoResetSelectedRows: false, to useTable function
  • Write a click handler for the radios by hand

    onClick={() => setSelectedRowId(row.id)}

enter image description here

I have put together the working code here. https://codesandbox.io/s/objective-faraday-gzf7y

Notes:

Michael Nelles
  • 5,426
  • 8
  • 41
  • 57
gdh
  • 13,114
  • 2
  • 16
  • 28
  • I am trying to exclusively select only 1 row at at time, and I see that your code only does this if including ``, can you please explain why that is? – SAKURA Aug 17 '20 at 16:25
  • 1
    React.StrictMode is not required. Although good to have. use toggleAllRowsSelected to set all rows as unchecked. In the example above, add toggleAllRowsSelected to line #92 under Cell logic and then onclick do toggleAllRowsSelected(false) before updateSelectedRowId – Mayukh Raaj Nov 20 '20 at 13:24
2

Based on previous answers, the solution below is with some improvements

  1. Change Checkbox to Radio Input

    Inside IndeterminateCheckbox Component

    Remove  <input type="checkbox" ref={resolvedRef} {...rest} />*/}
    Add     <input type="radio" ref={resolvedRef} {...rest} />
    
  2. a) Set the initial state if you want to autoselect any row initially

    b) Deselect all the radio buttons

    c) row.getToggleRowSelectedProps().checked give the current state of the radio button of that row. So toggling that value accordingly. i.e

    if checked -> change to unchecked and

    if unchecked -> change to checked

    // This selectedRowIds state gives the information about which row is selected currently.
    const{state: { selectedRowIds }}=useTable(
    {
     ....
     initialState: {
          columns,
          data,
          selectedRowIds: { 2: true },  //a) I want my second row to be autoselected initially
       },
     },
     useRowSelect,
         hooks => {
             hooks.visibleColumns.push(columns => [
                 {
                     id: "selection",                    
                     Cell: ({ row, toggleAllRowsSelected, toggleRowSelected }) => {                      
                        const currentState = row.getToggleRowSelectedProps();
                        return (
                           <IndeterminateCheckbox
                              {...currentState}
                              onClick={() => {
                                // b)
                                  toggleAllRowsSelected(false);
                                // c)
                                  toggleRowSelected(row.id, !currentState.checked);
                          }} />)
    
                        }},
                          ...columns
                        ]);
                        })
    
Dipesh KC
  • 2,273
  • 1
  • 15
  • 19
0

In case someone is still struggling with this, I found different solution.

IndeterminateCheckbox is same with slight change for input type:

const IndeterminateCheckbox = React.forwardRef(
    ({ indeterminate, ...rest }, ref) => {
        const defaultRef = React.useRef();
        const resolvedRef = ref || defaultRef;

        React.useEffect(() => {
            resolvedRef.current.indeterminate = indeterminate;
        }, [resolvedRef, indeterminate]);

        return (
            <>
                {/*<input type="checkbox" ref={resolvedRef} {...rest} />*/}
                <input type="radio" ref={resolvedRef} {...rest} />
            </>
        );
    }
);

Then onClick we deselect all rows, and select "clicked" row. :)

 const {
            getTableProps,
            getTableBodyProps,
            headerGroups,
            rows,
            prepareRow,
            toggleAllRowsSelected,
            toggleRowSelected,
            state: { selectedRowIds },
        } = useTable(
            {
                columns,
                data,
            },
            useRowSelect,
            hooks => {
                hooks.visibleColumns.push(columns => [
                    // Let's make a column for selection
                    {
                        id: "selection",
                        // The cell can use the individual row's getToggleRowSelectedProps method
                        // to the render a checkbox
                        Cell: ({ row }) => {
                            return (
                                <div>
                                    <IndeterminateCheckbox
                                        {...row.getToggleRowSelectedProps()}
                                        onClick={() => {
                                            toggleAllRowsSelected(false);
                                            toggleRowSelected(row.id, true);
                                        }}
                                    />
                                </div>
                            );
                        }
                    },
                    ...columns
                ]);
            }
        );
Ika
  • 11
  • 1