one-hand-octopus
one-hand-octopus

Reputation: 2763

How to make clicking an anchor equivalent to clicking a details tag?

I have a <details> tag, on click of it toggles some content. Now I have an <a> tag underneath it, on click of the <a> tag I'd like to toggle the same content, i.e. clicking the <a> should be equivalent to clicking the <details>. Here is a code snippet I've tried:

import React, { useState } from "react";
import ReactDOM from "react-dom";

const Menu = ({ toggleDetails }) => {
  return (
    <div>
      <a href="/#" onClick={toggleDetails}>
        Open
      </a>
    </div>
  );
};

const Details = (isOpen) => {
  return (
    <details>
      <summary>Hello</summary>
      {isOpen ? <div>Hi</div> : null}
    </details>
  );
};

const App = () => {
  const [isOpen, setIsOpen] = useState(false);
  const toggleDetails = () => {
    setIsOpen(isOpen ? false : true);
  };
  return (
    <div>
      <Details isOpen={isOpen} />
      <Menu toggleDetails={toggleDetails} />
    </div>
  );
};

ReactDOM.render(<App />, document.getElementById("container"));

Here on click of 'Hello', it toggles 'Hi'. I'd like to do the same thing on click of 'Open', i.e. toggles 'Hi'. How can I do it? The conditional rendering does not work. Should I use a ref to access the 'open' property of the <details> tag?

EDIT:

I also tried the ref solution as follows but it didn't work:

const Details = (isOpen) => {
  const detailsRef = useRef();
  // detailsRef.current.open = isOpen
  return (
    <details ref={detailsRef}>
      <summary>Hello</summary>
      <div>Hi</div>
    </details>
  );
};

Upvotes: 0

Views: 192

Answers (3)

Mohebifar
Mohebifar

Reputation: 3411

I assume you are trying to use the details tag's native toggle functionality. In order to do that, you need to control the open/closed state via the open attribute. You should then use the onToggle event to detect when the summary element is clicked, so you can keep your component's state in sync with the actual DOM.

const Menu = ({ setIsOpen }) => {
  return (
    <div>
      <a
        href="#"
        onClick={() => {
          setIsOpen((prev) => !prev);
        }}
      >
        Open
      </a>
    </div>
  );
};

const Details = ({ isOpen, setIsOpen }) => {
  return (
    <details
      open={isOpen}
      onToggle={(event) => {
        setIsOpen(event.target.open);
      }}
    >
      <summary>Hello</summary>
      <div>Hi</div>
    </details>
  );
};

const App = () => {
  const [isOpen, setIsOpen] = useState(false);

  return (
    <div>
      <Details isOpen={isOpen} setIsOpen={setIsOpen} />
      <Menu setIsOpen={setIsOpen} />
    </div>
  );
};

Upvotes: 1

dpwr
dpwr

Reputation: 2812

Pretty sure all you need to do is ensure that details open attribute is set to true or false depending on if you want it open or.not.

<details open={isOpen}>...</details>

Upvotes: 0

Arber Gjonaj
Arber Gjonaj

Reputation: 1

You need to transfer information between both components to do that you either needs to: 1: State penetration, 2: Redux.

You are attempting to change a component that is not connected to the one you are calling. The Hi div is on the Details component which is not in direct relationship with the Menu component. Now regarding your specific problem, you can do it by pushing the state on a higher component which in this case is App.js.

Now I do not understand if you are trying to make the app work in this way as a coding challenge or if you do not know better. If it is the latter please reply in the comments so I can provide a direct solution.

Upvotes: 0

Related Questions