I have a simple table on my website listing devices and their characteristics (in the example at the link below there will be a shortened version of the table).
import "./styles.css";
import { SubMenu } from "./SubMenu";
const subMenuSlice = <SubMenu />;
const nodes = [
{
id: "0",
name: "Samsung Galaxy",
subMenu: subMenuSlice
},
{
id: "0",
name: "Iphone",
subMenu: subMenuSlice
}
];
export default function App() {
return (
<table>
<tbody>
{nodes.map((val, key) => (
<tr key={key}>
<td>{val.name}</td>
<td>{val.subMenu}</td>
</tr>
))}
</tbody>
</table>
);
}
SubMenu.tsx
import { useState } from "react";
import AppsIcon from "@mui/icons-material/Apps";
import * as DropdownMenu from "@radix-ui/react-dropdown-menu";
import "./styles.css";
export const SubMenu = () => {
const [isOpen, setIsOpen] = useState(false);
return (
<DropdownMenu.Root open={isOpen} onOpenChange={setIsOpen}>
<DropdownMenu.Trigger>
<AppsIcon className="sss" />
</DropdownMenu.Trigger>
<DropdownMenu.Portal>
<DropdownMenu.Content
side="bottom"
sideOffset={-30}
align="start"
alignOffset={80}
>
<button className="style-button">Edit </button>
<button className="style-button">Make </button>
<button className="style-button">Delete </button>
</DropdownMenu.Content>
</DropdownMenu.Portal>
</DropdownMenu.Root>
);
};
styles.css
.sss {
visibility: hidden;
}
tr:hover .sss {
background: gray;
visibility: visible;
}
tr:hover {
background: gray;
visibility: visible;
pointer-events: initial !important;
}
.style-button:hover {
background-color: aqua;
}
https://codesandbox.io/s/romantic-rgb-5t7xkq
As you can see, when you hover over any of the lines, the entire line turns gray and an additional button appears. By clicking on this button the user gets a submenu.
Description of the problem: the problem is that when the user moves the cursor to the submenu, the hover (gray) disappears from the table row. Please tell me how to keep the hover enabled while the submenu is active (open)
2
Answers
I would keep track of some state, for example the current
id
of the item that is being "hovered". Then for that item add an extra class and style it depending on that class, in your example:App.tsx
styles.css
You must make sure in this example all ids are unique. If this cannot be the case, use another unique value.
Updated
If you want to have this state not only when your component is being hovered, but generally when active, I would do the following:
Rename the state to "isActive" and pass the value from the subcomponent to the parent so you can use this value on your className. Also, re-add your original styles for when the component is being hovered, in that case you will have the styles both when the component is hovered and while it is active. This is how you would do it:
App.tsx
styles.css
SubMenu.tsx
If you’re not desperate to support old browsers you can use :has() CSS relational pseudo-class to style the
tr
when it contains abutton
havingdata-state="open"
. One big caveat is that this is not yet supported in Firefox. However, at the time of writing, it does have global support of ~87.53%.So if that’s for you, the approach is as follows:
Give
.sss
descendent of open buttons a grey bg:tr td button[data-state="open"] .sss {...}
Give
tr
that contains (/’has’) an open button a grey bg:tr:has(button[data-state="open"]) {...}
Your complete style.css looks like this:
Demo: https://codesandbox.io/s/sweet-tess-zcf23k