Why can't a <button> element contain a <div>?
Asked Answered
C

5

29

My company is building a website and we had some problems with a JavaScript library not replacing something. We decided to throw our HTML in to the W3C validator and it informed us it's illegal to have a <div> tag inside a <button> tag.

<button class="button" type="submit">
    <div class="buttonNormalLargeLeft"><!--#--></div>
    <div class="buttonNormalLargeCenter">Search Flights</div>
    <div class="buttonNormalLargeRight"><!--#--></div>
</button>

Results in:

Line 287, Column 46: Element div not allowed as child of element button in this context. (Suppressing further errors from this subtree.)

Edit: To clarify what we're trying to do here. We want to make a button with rounded corners that doesn't rely on box-radius. We made 3 divs in the button element each has his own sprite to make it appear rounded and allow for different widths. Other resources state that the button element was created for users that wanted a button to contain sub elements such as images but divs appear to be invalid for some reason.

Why are divs not allowed inside button elements?

What is the desired solution to this issue?

Edit2:

Why not use input? Because inputs can't have the desired layout

Why not use divs? Because users without JavaScript won't be able to submit the form.

Community answered 8/4, 2013 at 17:39 Comment(8)
What are you trying to do? It seems there is a better way. What's wrong with using button normally? I don't understand what you're trying to accomplish here. are you trying to center your label?Renzo
w3schools.com/tags/tag_button.aspRenzo
@Thomas Wright The css classes have separate images to give the button rounded corners. We do not want to use the CSS property for this yet.Community
It's not a bad question, what you're doing is actually widely used, (one of the benefits of the <button> IMHO), but it just doesn't validate. I would say if it works, leave itPollster
You could use a div for the button, display & submit with JS, then use a standard button in <noscript> tags for those without JS... Or, as others have suggested, just ignore validation because it seems to work in-browser even though it's against spec.Jellicoe
@Community - the reason we have js and css is to add functionality and capability to [x]html. Have you solved your problem yet? I would recommend that you not shy from such utilities. They have become an integral part of web design and development. Despite the general consensus in this thread, you can keep to w3c standards, xbrowser compatibility, and make it look exactly the way you want. Don't worry about that <.0001 percent that have jilted their technical experience and turned off js and don't be turned off by css. If [x]html was a picture, css would be the color.Renzo
How about just adding an <img /> tag inside your button? Validates and you get to create your button with rounded edges without box-radius and will work on any browser.Vigorous
Instead of divs, use spans with css of display:inline-block, so that you can size them.Intwine
D
5

Per the HTML standard a <button> may only contain Phrasing content. A div element is not a valid element for Phrasing Content.

Dishonor answered 29/7, 2020 at 21:56 Comment(0)
V
4

Well I posted a comment but no love.

You can achieve a W3C valid button by simply putting an image inside the button.

Fiddle

Granted you'll have to create your images and add the text to them. But since you've already created images for the corners that shouldn't be too hard.

Also image sprites are a great thing.

.test {
  width: 258px;
  height: 48px;
  background: none;
  border: 1px solid transparent;
}
.test:active {
  outline: 0;
}
.test > img {
  width: 258px;
  height: 45px;
  opacity: 1;
  background: url('http://www.copygirlonline.com/wp-content/plugins/maxblogpress-subscribers-magnet/lib/include/popup1/images/btn/blue-button.png');
  background-position: -3px 0px;
}
.test > img:hover {
  background-position: -3px -50px;
}
<button class="test">
  <img src="http://alistapart.com/d/cssdropshadows/img/shadowAlpha.png" />
</button>

If you want to stick with 3 images here's an updated version.

button {
  margin: 0;
  padding: 0;
  border: none;
}
<button>
  <img src="http://placehold.it/50x50" /><img src="http://placehold.it/50x50" /><img src="http://placehold.it/50x50" />
</button>

Also, without additional CSS, it seems you need to keep all of the <img /> tags on the same line or it treats the images as having space between them.

Vigorous answered 25/3, 2015 at 19:47 Comment(1)
This is obviously a pretty old question of mine, and I'd love to approve an answer but... The reason we used 3 images is because the buttons needed to be able to have variable width. Using a single image plus stretching will give it weird corners. Althought I think your solution is probably possible if you just include 3 images in a <button> element?Community
P
2

If you want to use a custom button, you'll have to replace the button tag with a div or an input. It looks like a div is what you want in this case. You'll just have to add any necessary event handlers, (for your submit).

This might help clarify things a bit.

Pollster answered 8/4, 2013 at 17:42 Comment(4)
Like I commented above, we want buttons with rounded corners in browsers that do not yet support border-radius such as IE8. The 3 divs all have their own image.Community
The input element does not allow rounded corners, and divs do not function as buttons for users without javascript.Community
@Community You stated in your question that you were using Javascript. So why can't you use it here?Pollster
FYI for anyone who happens upon this answer that changing a button to a div will break accessibility and should be avoided, and if you must do it then make sure to use the correct aria attributes and follow the accessibility guidelines to do so.Ainsley
R
1

If you're using a form, you could change the button to be a clickable div instead. For example:

<div role="button" onclick="$(this).closest('form').submit()">
    <!-- your child content here -->
</div>

Alternatively, if you know the form name or ID you could change the inline javascript to something like document.getElementById("form-id").submit()

Resh answered 1/3, 2017 at 18:14 Comment(0)
E
0

Suuuuper old question, but since I found it while searching for this answer myself, you can achieve this with a slight html re-structure and some simple CSS. Make the button the last child of a parent div, make it cover the div, and make it transparent.

I'm assuming you finished your website 9 years ago, but I'll explain this in full anyway in case others stumble across this in another 9 years.

HTML

<div class="buttonParent">
    <div class="buttonNormalLargeLeft"><!--#--></div>
    <div class="buttonNormalLargeCenter">Search Flights</div>
    <div class="buttonNormalLargeRight"><!--#--></div>
    <button class="button" type="submit"></button>
</div>

CSS

.button{
  position: absolute;
  left: 0px;
  top: 0px;
  width: 100%;
  height: 100%;
  background: transparent;
  border: none;
}

You could also use opacity: 0 instead of a transparent background and no border, but that removes your ability to tab to it.

You still have access to .button:hover, .button:active and .button:focus for the button itself, which can be used, for example, to add a background to the button itself with a very low opacity for a simple hover effect.

Or, if you want to go a little further down the rabbit hole, you can directly add or replace classes on the parent object, this will allow you to overwrite the previous classes and do whatever you want to the display of the button.

Non-JS

<button class="button" 
onclick="this.parentElement.classList.replace('buttonParent', 'buttonParentClicked')" 
onblur="this.parentElement.classList.replace('buttonParentClicked', 'buttonParent')"
type="submit"></button>

For example, ".buttonParentClicked .buttonNormalLargeLeft" will override the CSS you have for .buttonNormalLargeLeft, so you can use it to completely change the images and styles you have there.

And of course, if that's still not enough and you need more functionality on the parent, you can do whatever you want with JS.

HTML

<button class="button" onclick="myFunction()" type="submit"></button>

JS

myFunction(e){
    const parent = e.target.parentElement;
    //whatever you want to parent;
}
Embay answered 25/8, 2022 at 15:7 Comment(2)
I appreciate an answer so many years later. Your answer works but to provide some extra context. At the time this question was asked I'm not sure all those CSS tricks were universally supported. We were still concerned with IE6 or whatever people used 9 years ago. Today there are many ways to accomplish the effect we were looking for in a much more idiomatic way.Community
And I appreciate the response! It did occur to me after I went to bed that that may be the case! Not sure if this would have worked then or not! I just figured that since I needed to do this research for myself anyway and found your question while trying to find the answer myself, I would share it for future searchers!Embay

© 2022 - 2024 — McMap. All rights reserved.