React Table - radio input for useRowSelect

Viewed 7153

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

3 Answers

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:

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
                        ]);
                        })
    

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
                ]);
            }
        );
Related