Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't <fieldset> be flex containers?

Tags:

html

css

flexbox

People also ask

Can buttons be flex items?

In addition to <button> elements, you may find this constraint applying to <fieldset> and <legend> elements, as well. See the bug reports below for more details. Note: Although they cannot be flex containers, <button> elements can be flex items.

Can an element be both a flex item and a flex container?

Flex items within a flex container can be laid out either horizontally or vertically, but not both. If you want to lay out items in both dimensions, you'll need to nest a flex container inside another one. In this example we apply display: flex to both the outer container and to the red flex item.

Can we use Fieldset outside form?

You can use any form elements outside of an actual form, since most of them can be used with JavaScript utilities outside the form. The form is only needed if you plan on allowing the user to submit the data with it.

Can a Fieldset have a class?

Classes (i.e. classnames) are used for styling the fieldset element. Multiple classnames are separated by a space. JavaScript uses classes to access elements by classname. Tip: class is a global attribute that can be applied to any HTML element.


According to Bug 984869 - display: flex doesn't work for button elements,

<button> is not implementable (by browsers) in pure CSS, so they are a bit of a black box, from the perspective of CSS. This means that they don't necessarily react in the same way that e.g. a <div> would.

This isn't specific to flexbox -- e.g. we don't render scrollbars if you put overflow:scroll on a button, and we don't render it as a table if you put display:table on it.

Stepping back even further, this isn't specific to <button>. Consider <fieldset> and <table> which also have special rendering behavior:

data:text/html,<fieldset style="display:flex"><div>abc</div><div>def</div>

In these cases, Chrome agrees with us and disregards the flex display mode. (as revealed by the fact that "abc" and "def" end up being stacked vertically). The fact that they happen to do what you're expecting on <button style="display:flex"> is likely just due to an implementation detail.

In Gecko's button implementation, we hardcode <button> (and <fieldset>, and <table>) as having a specific frame class (and hence, a specific way of laying out the child elements), regardless of the display property.

If you want to reliably have the children reliably arranged in a particular layout mode in a cross-browser fashion, your best bet is to use a wrapper-div inside the button, just as you would need to inside of a <table> or a <fieldset>.

Therefore, that bug was marked as "resolved invalid".

There is also Bug 1047590 - display: flex; doesn't work in <fieldset>, currently "unconfirmed".


Good news: Firefox 46+ implements Flexbox for <fieldset>. See bug 1230207.


I find out this might be a bug on Chrome and Firefox where legend and fieldset are replaced elements.

Bugs Reported:

Bug Chrome (fixed since v86)
Bug Firefox (fixed since v46)

A possible Workaround:

A possible workaround would be using <div role="group"> in HTML, and applying in CSS div[role='group'] as selector.


UPDATE

In Chrome version 83 button can work with the display: inline-grid/grid/inline-flex/flex, you can see the demo below:

button {
  display: inline-flex;
  height: 2rem;
  align-items: flex-end;
  width: 4rem;
  -webkit-appearance: none;
  justify-content: flex-end;
}
<!-- 

The align-items keyword should fail in Chrome 81 or earlier, but work in Chrome 83 or later. To see the error, the button needs styles that make it more of an extrinsic container. In other words, it needs a height or width set. 
 
-->
<button>Hi</button>
<input type="button" value="Hi">

Please star the Chrome bug to increase bug priority

This is a bug in Chrome. Please add a star to this issue to increase it's priority to be fixed: https://bugs.chromium.org/p/chromium/issues/detail?id=375693

In the mean time, I created these three Code Pen examples to show how to work around the issue. They are built using CSS Grid for the examples but the same techniques can be used for flexbox.

Using aria-labelledby instead of legend

This is the more propper way to deal with the problem. The downside is that you have to deal with generating unique IDs applied to every fake legend element.

https://codepen.io/daniel-tonon/pen/vaaGzZ

<style>
.flex-container {
    display: flex;
}
</style>

<fieldset aria-labelledby="fake-legend">
    <div class="flex-container">
        <div class="flex-child" id="fake-legend">
            I am as good accessibilty wise as a real legend
        </div>

        ...

    </div>
</fieldset>

Using role="group" and aria-labelledby instead of fieldset and legend

If you need the flex-container to be able to stretch to the height of a sibling element and then also pass that stretch onto its children, you will need to use role="group" instead of <fieldset>

https://codepen.io/daniel-tonon/pen/BayRjGz

<style>
.flex-container {
    display: flex;
}
</style>

<div role="group" class="flex-container" aria-labelledby="fake-legend">
    <div class="flex-child" id="fake-legend">
        I am as good accessibilty wise as a real legend
    </div>

    ...

</div>

Creating a fake duplicate legend for styling purposes

This is a far more hacky way to do it. It is still just as accessible but you don't have to deal with IDs when doing it this way. The main down side is that there is going to be duplicate content between the real legend element and the fake legend element.

https://codepen.io/daniel-tonon/pen/zLLqjY

<style>
.screen-reader-only {
    position: absolute;
    opacity: 0;
    pointer-events: none;
}
.flex-container {
    display: flex;
}
</style>

<fieldset>
    <legend class="screen-reader-only">
        I am a real screen-reader accessible legend element
    </legend>

    <div class="flex-container">
        <div class="flex-child" aria-hidden="true">
            I am a fake legend purely for styling purposes
        </div>

        ...

    </div>
</fieldset>

Legend MUST be a direct decendent

When you are first trying to fix this yourself, you will probably try doing this:

<!-- DO NOT DO THIS! -->
<fieldset>
    <div class="flex-container">
        <legend class="flex-child">
            Broken semantics legend text
        </legend>

        ...

    </div>
</fieldset>

You will discover it works, and then you will probably move on without giving it a second thought.

The problem is that putting a div wrapper between the fieldset and the legend breaks the relationship between the two elements. This breaks the semantics of fieldset/legend.

So by doing this, you have defeated the whole purpose of using fieldset/legend in the first place.

Also, there isn't much point in using a fieldset if you don't give that fieldset a legend.


In my experience, I've found that neither <fieldset>, nor <button>, nor <textarea> can properly use display:flex or inherited properties.

As others have already mentioned, bugs have been reported. If you want to use flexbox to control ordering (e.g. order:2), then you'd need to wrap the element in a div. If you want flexbox to control actual layout and dimensions, then you may want to consider using a div, instead of the input control (Which stinks, I know).