DEV Community

Devin Rasmussen
Devin Rasmussen

Posted on

button cannot appear as a descendant of button

Let's say we're given the following mock from a designer to list files in rows.

Alt Text

Each row should be clickable. There is also a button of "other options" on each row that triggers a different event. Therefore, there are two clickable elements, one which appears to encapsulate the other.

I'm trying to be better at semantic HTMl so I initially wrote out a <button>, stripped it of its default styling and made it into row. Then I nested another <button> inside. That is when I experienced the react warning <button> cannot appear as a descendant of <button>.

I learned that for the HTML button there must be no interactive content descendant. Interactive content is content that is specifically intended for user interaction.

We are left with two options:

  1. Transform a non-semantic <div> into a clickable element
  2. Use styling to place one <button> on top of another

The first is completely possible. We simply have to include a few aria attributes for accessibility. The div might look something like this

<div tabindex="0" role="button">
  <div>file title</div>
  <button>other options</button>
</div>
Enter fullscreen mode Exit fullscreen mode

The other option was a little trickier but felt better to me. I don't claim to know all the ins and outs of semantic HTML but as I mentioned I'm increasingly trying to use the right tags wherever possible.

<div class='two-buttons'>
  <button class='row undo-button-styling'>
    <div>File 🤖 🎃</div>
  </button>
  <button class='other-options'>other options</button>
</div>
Enter fullscreen mode Exit fullscreen mode

There are a number of styling changes that need to happen (position relative parent, position absolute child, undoing button styling) but here is the finished codepen.

https://codepen.io/devcon/pen/GRqGQxZ

Top comments (4)

Collapse
 
athomsfere profile image
Austin French

I would have gone with the Div approach.

If you can't do it in plain Js out of the box, it's probably not the best option. Unless it has some other benefit (like a lot less code).

jsfiddle.net/athomsfere/35wakz2j/1/

<div class="fancy-div" onclick="fancyClick(this)">
  <div class="fancy-content">
  The things! 🐱‍🏍
  </div>

  <button type="button" class="fancy-button">
  Click me
  </button>
</div>

<div class="fancy-div" onclick="fancyClick(this)">
  <div class="fancy-content">
  Cake 🎂
  </div>

  <button type="button" class="fancy-button">
  Click me
  </button>
</div>

<div class="fancy-div" onclick="fancyClick(this)">
  <div class="fancy-content">
  Steamy 😤
  </div>

  <button type="button" class="fancy-button">
  Click me
  </button>
</div>
Enter fullscreen mode Exit fullscreen mode
function fancyClick(elem){  
  elem.classList.toggle('clicked');
}
Enter fullscreen mode Exit fullscreen mode
.fancy-div {
    display: flex;
    border-style: solid;
    border-color: red;
    border-radius: 5px;
    border-width: 1px;
    padding: 5px 5%;
    margin: 10px;
}

.fancy-div:hover {
  background-color: lightgray;
}

.fancy-content {
  float: left;
  width: 90%;
}

.fancy-button {
  float: right;
}

.clicked {
  border-color: orange;
  color: gray;
}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
dvnrsn profile image
Devin Rasmussen

I love seeing raw JS solutions like this. Too much we get lost in frameworks and it's a good reminder.

I believe the weakness of this solution is its inaccessibility. For example there are no tabs on the clickable rows. Additionally, screen readers will not register that the divs are serving as buttons.

Collapse
 
athomsfere profile image
Austin French

True, but I'd also say:

Scrolling through the page, it doesn't look like a button either. (I guess this is why I went straight to adding a hover effect).

Tabbable == fixable at least.

But I guess back to my original point: I tent to prototype the big idea in pure JS. And then move it to a framework or rewrite it as a reusable component where I can continue to work through enhancements like accessibility.

Collapse
 
daggron profile image
Abhay Sharma

But why it is invalid, can anyone tell, what bugs will it cause