A guide to using the up and down keys to switch focus between div elements in a react component with TypeScript and CSS

I am currently working with a scenario where data is being displayed within different div elements, and I wish to enable the selection/focus of a specific div when users use the up/down arrow keys.

While trying to achieve this functionality by using refs and ForwardRefs for child components in TypeScript code, I am facing some challenges. As I am relatively new to React, any suggestions or improvements on the provided code would be greatly appreciated.

Below are snippets of the code:

Option.ts

export interface Option {
id: number;
label: string;
value: string;
}

App.tsx

import React, { useRef, useEffect } from 'react';
import { Option } from './option';
import Options from './options';

export default function App() {
  const options: Option[] = [
    { id: 0, label: "Option 1", value: "12000" },
    { id: 1, label: "Option 2", value: "10000" },
    { id: 2, label: "Option 3", value: "11000" },
    { id: 3, label: "Option 4", value: "23000" }
  ];

  const [invTheme, setInvTheme] = React.useState("10000");
  const firstRef = React.createRef<HTMLDivElement>();
  const checkedRef = React.createRef<HTMLDivElement>();

  useEffect(() => {
    if (checkedRef.current) {
      checkedRef.current.focus();
    } else if (firstRef.current) {
      firstRef.current.focus();
    }
  }, []);

  return (
    <div className="App">
      {
        options.map((option, i) => {
          const { id, label, value } = option;
          const checked = invTheme === value;

          return (
            <div key={i}>
              <Options
                id={id}
                label={label}
                value={value}
                checked={checked}
                onChange={() => {
                  setInvTheme(value);
                }}
              />
              <br/><br/>
            </div>
          )
        })
      }
    </div>
  );
}

Options.tsx

import React, { useEffect } from 'react'
import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
import Grid from '@material-ui/core/Grid';

const useStyles = makeStyles((theme: Theme) =>
  createStyles({
    root: {
      flexGrow: 1,
    },
    div: {
      padding: theme.spacing(2),
      margin: 'auto',
      maxWidth: 700,
      border: '1px solid Gray'
    },
    selectedDiv: {
      padding: theme.spacing(2),
      margin: 'auto',
      maxWidth: 700,
      border: '2px solid Blue'
    }
  }),
);

export default function Options(props: any) {
  const classes = useStyles();

  const handleOnClick = (e: any) => {
    if (e.type === "click" && e.clientX !== 0 && e.clientY !== 0) {
      onChange({ target: value });
    }
  };

  const { id, label, value, onChange, checked } = props;
  
  return (
    <div>
      <div className={checked ? classes.selectedDiv : classes.div} onClick={handleOnClick}>
        <Grid container spacing={2}>
          <Grid item>
            <input id={id} type="radio" name="type" aria-label={label} checked={checked} value={value} onChange={onChange}/>
          </Grid>
          <Grid item>
            {label}
          </Grid>
        </Grid>
      </div>
    </div>
  );
}

https://i.sstatic.net/PiaLz.png

Answer №1

This is my approach to the solution.

I utilized the checked props to manage the style property of the div.

See below for the code snippets:

options.tsx:

import React, {useEffect} from 'react'
import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
import Grid from '@material-ui/core/Grid';

 const useStyles = makeStyles((theme: Theme) =>
  createStyles({
        root: {
         flexGrow: 1,
         },
         div: {
  padding: theme.spacing(2),
  margin: 'auto',
  maxWidth: 700,
  border:`1px solid Gray`,
 
},
selectedDiv: {
  padding: theme.spacing(2),
  margin: 'auto',
  maxWidth: 700,
  border:`1px solid Gray`,
},
selected: {
  
}
}),);

 export default function Options(props:any) {
  const classes = useStyles();
  const [selectedDiv, setSelectedDiv] = React.useState(false);
  const { id, label, selected, value, onChange, checked } = props;
  useEffect(()=>{
       if(selected) setSelectedDiv(true);
     },[])

 const handleOnClick = (e:any) => {
    if (e.type === "click" && e.clientX !== 0 && e.clientY !== 0) {
      setSelectedDiv(true);
     
      onChange({target:value});
    }
  };



return (
  <div>
    <div className={selectedDiv  ?  classes.selectedDiv :classes.div}  onClick={handleOnClick}style = {checked && selectedDiv? {border: `2px solid Blue`,maxWidth: 700,}:{}} >
    <Grid container spacing={2} >
        <Grid item>
            <input id={id} type="radio" name="type" aria-label={label} checked={checked}  value={value} onChange={onChange}/>
        </Grid>
        <Grid item >
            {label}
        </Grid>
    </Grid>
  </div>
  </div>
);}

App.tsx:

import React, {useRef, useEffect} from 'react';
 import { option } from './option';
 import Options from './options' 


 

 export default function App() { 
  const options : option[] = [
    { id:0, label : "Option 1", selected : false, value:"12000"},
    { id:1, label : "Option 2", selected : true,  value:"10,000" },
    { id:2, label : "Option 3", selected : false, value:"10000"},
    { id:3, label : "Option 4", selected : false, value:"23000" }
   ];


   const [invTheme, setInvTheme] = React.useState("12000");
   const firstRef = React.createRef<HTMLDivElement>();
   const checkedRef = React.createRef<HTMLDivElement>(); 
 

  useEffect(() => {
      if (checkedRef.current) {
          checkedRef.current.focus();
      } else if (firstRef.current) {
      firstRef.current.focus();
   }
  }, []);


   return (
     <div className="App">
      {
      options.map((option, i) => {
        const {id, label, selected, value} = option;
        const checked = invTheme === value;
 
        return (
          <div key={i}  >
            <Options id={id} label={label} selected={selected} value={value} checked={checked}
             onChange={() =>{
              setInvTheme(value);
            }}   />
            <br></br>
          </div>
        )
      })
   }
</div>
  );
 }

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Why won't the jQuery function trigger when I click, but only responds when I move the cursor?

I am currently working on a website that includes a basic CSS style switcher. The function responsible for handling the theme button clicks is shown below: <script> $(function() { $(".light").click(function(){ $("link").attr("href", ...

Issue with locating assets in Angular 6 build

Hey there! I'm currently facing an issue while trying to build my angular project. In the project, I am using scss with assets, and below is a snippet of how I have defined the background image: .ciao { background-image: url("../../assets/images/bc ...

Typescript: require generic types to include specific keys at all times

Is there a way to ensure that the function below only accepts a data object if it contains an id key, and then allows us to access the id from the data object? function someFuntion<T>(data : T){ const id = data['id'] //Error : Element imp ...

Enhance your WooCommerce shopping experience by incorporating a variety of personalized checkout fields organized into two distinct

I have implemented custom code to create unique checkout fields based on the number of products in a customer's cart. Each product requires 4 customized checkout fields, displayed in two columns side by side. The expected result is as follows: co ...

What could be causing the href to malfunction on my local website?

I'm currently working on adding a new link that directs to a local HTML website within a menu list on a website. The main website is in ASPX format, but my focus is on the HTML version. The link I want to add leads to an HTML website stored on my loca ...

Utilizing Arrays in Typescript within the Angular Framework

I have developed a Rest API that provides data to populate two drop-down lists in a form. The information retrieved from the API is grabbed by the Angular backend and assigned to the respective drop-downs. Rather than making separate Get requests for each ...

Tips for concealing an entire menu on WP, with the exception of items labeled as current-menu-ancestor

On my Wordpress site, I am faced with a simple problem to solve. I have a primary menu at the top and a secondary menu on the left side. While the top menu only contains level 1 items, the left menu has all the items. To customize the left menu, I am utili ...

Ensuring DIVs are completely contained within their parent DIV using Fullscreen CSS and a height of

I found a nearly-perfect design using the code below: https://i.sstatic.net/56i2E.png This code provides the layout mentioned: <!DOCTYPE html> <head> <meta charset="UTF-8"> <link rel="stylesheet" href="http://maxcdn. ...

Following the update to Next.js version 14.1, a createElement error is being encountered when using Apollo Client

I have identified the issue to be caused by upgrading Nextjs from version 14.0.4 to 14.1.0. The problem seems to originate from the client-side instantiation of Apollo Client. I am following the guidelines in Next.js for third-party package providers Err ...

Larger Material UI icons contribute to significant Cumulative Layout Shift

I am facing an issue with my website that is built using React, Nextjs, and Material UI Every time the page loads, there is a significant Cumulative Layout Shift caused by an SVG Material UI Icon that initially renders large before adjusting to the styled ...

Steps for positioning a logo to the left and navigation to the right with HTML and CSS

Could someone assist me in aligning a logo on the left and navigation menu on the right using HTML and CSS? I envision it to look like the image displayed. I have tried various approaches to adjust my CSS styling, but nothing seems to be working as inten ...

What are some ways to customize the text and button location for Bootstrap 5's file input?

Bootstrap 5's input type file seems too simplistic. Check it out here https://i.stack.imgur.com/VZ0h5.png I am curious about three things: Can the "Choose file" button be moved to the right? Is it possible to change the message that says "No files ...

the replication of a column within one single column

I have discovered that in order to arrange items in a column using bootstrap-5, the code should look like this: <link href="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="a3c1ccccd7d0d7d1c2d ...

The process of removing and appending a child element using WebDriverIO

I am trying to use browser.execute in WebDriverIO to remove a child element from a parent element and then append it back later. However, I keep receiving the error message "stale element reference: stale element not found". It is puzzling because keepin ...

Conceal the second click action within the anchor tag

Is there a way to hide the second click event on all anchor tags except those that trigger popupfun? I have a sample page set up. [Check out the JS Fiddle here][1] http://jsfiddle.net/ananth3087/LgLnpvf4/15/ Link Anchor Tags: The page includes two ...

Manipulate only the elements inside the designated container

My CSS/bootstrap file is quite extensive and the styles are affecting more than just the elements I intended to target. While I want it to have a broad impact, the CSS changes are impacting the entire page. Renaming every element to [name].slider is not ...

What is the most effective way to retrieve data from a URL and process it using reactjs?

Looking to consume JSON data from a URL, here is an example of the JSON structure: { "results": [ ... ], "info": { ... } } I aim to display the fetched data as a component property. What is the most efficient way to achie ...

Encountering H10 Error Code When Deploying React App on Heroku

I recently developed a React app using create-react-app. It functions perfectly on my local server, but I encountered issues when attempting to deploy it on Heroku. Unfortunately, the application crashes upon deployment, and I am unsure of the exact reason ...

`Finding it difficult to halt the spread of events in reactJs`

One of my conditions involves a simple dropdown menu: handleDropdown = (e) => { if (e.type === "focus") { console.log("inside dropdown focus"); this.setState({ dropDownDis: "block" }) } else if (e.type === "blur") { console.lo ...

Only half of the image is responsive to hover effects

Just starting out with coding and running into an issue... My social media icons are supposed to turn pink on hover using a second image, but for some reason it's only showing up on the bottom half. Any suggestions? CSS: a.twitter:hover { backgr ...