-
Notifications
You must be signed in to change notification settings - Fork 2.1k
text-field: allow floating label to be outside of notched-outline markup #5326
Comments
Thanks for the issue! I'm not entirely sure I understand why the label's position would be related to prefix or suffix. No matter how wide a prefix is, the label's position does not change. Prefix and suffix are considered "part of" the input. In your diagram,
The only time a label's horizontal position changes is if there's a leading icon. We are actively working on prefix/suffix in #1892, the DOM structure will look something similar to this: <span class="mdc-text-field__prefix">$</span>
<input class="mdc-text-field__input" value="42">
<span class="mdc-text-field__suffix">.00</span> Would it be possible to incorporate our prefix/suffix work into mdc-form-field? |
@asyncLiz Thanks for the quick reply! I think my graphic was most likely confusing. The actual text-field is the whole container surrounded by the red border. The red border should actually be the outline of the text-field. So we actually consider prefix and suffix as part of the input, but just in a perspective of how it will be composed in the DOM, the native In our implementation of the Angular Material form-field, we use the prefix and suffix containers for both icons and text and consider a leading icon as prefix. That's probably wrong though in terms of the spec since leading icons and prefixes have different semantics (i.e. label needs to shift horizontally for icons as you explained). So let's just talk about this issue in in terms of leading icons where the label needs to be shifted (as you said). In that case, consider that the leading icons have an unknown width. How would one be able to ensure that the floating label does not overlap the icon in the non-floating state? I see that MDC achieves this by just adding more horizontal padding to the input, and by shifting the floating label by So to make this work, we want the label to be a children of Does this somehow make sense to you? If it's still somewhat unclear please let me know 😄 Thanks! |
I would definitely recommend treating prefix/suffix and icons differently instead of as the same container. I think you'll run into quite a few problems. Off the top of my head, prefix/suffix padding between them and the input is different than icons, and changes if the text is end vs start aligned. How close is your implementation following the spec? I can talk with design and see if there's capability for icons to be wider than 24px. I think the biggest problem we'll run into is that the notched outline requires the label to be a child, so that it can querySelector it. I'll do some experiments this morning and see if I can think of a way that would be possible. |
We think of the prefix and suffix as simple containers where people can put in arbitrary elements. I think we have a ambiguous naming for this though since it's technically not necessarily matching the prefix/suffix semantics explained in the Material Design specification. For things like icons we'll have some additional default styling inside prefix/suffix containers to ensure there is proper spacing. I totally realize that this might have downsides but we mostly need to do that for backwards compatibility with our old implementation of the form-field and I think in general it makes sense to give users the flexibility to put in anything they want (e.g. some people put in icons wrapped by buttons). In any case though, for icons the goal is to be visually the same as the current leading icon support available in MDC text-field (just with providing the flexibility and backwards compatibility)
Indeed. That is the problem I ran into. If the label would be decoupled from the notched-outline, then this issue would be solved for us. It should be possible to just keep the current behavior, but provide a possibility to pass in a label element. (It might be necessary to modify how the necessary styles are applied to the label though; could be through a class that is added to the label element) Also thanks for looking if this is possible! |
…stom controls better * Fixes the baseline of form-field controls and their inputs. Previously the baseline was incorrect due to flex alignment. * Improves support for custom form-field controls by ensuring that spacing applied to MDC inputs, also applies to custom controls. * The same will be needed for the outline appearance, but unfortunately we cannot apply any spacing to the infix until we find a solution for: material-components/material-components-web#5326
…stom controls better * Fixes the baseline of form-field controls and their inputs. Previously the baseline was incorrect due to flex alignment. * Improves support for custom form-field controls by ensuring that spacing applied to MDC inputs, also applies to custom controls. * The same will be needed for the outline appearance, but unfortunately we cannot apply any spacing to the infix until we find a solution for: material-components/material-components-web#5326
…stom controls better * Fixes the baseline of form-field controls and their inputs. Previously the baseline was incorrect due to flex alignment. * Improves support for custom form-field controls by ensuring that spacing applied to MDC inputs, also applies to custom controls. * The same will be needed for the outline appearance, but unfortunately we cannot apply any spacing to the infix until we find a solution for: material-components/material-components-web#5326
…stom controls better (#18161) * Fixes the baseline of form-field controls and their inputs. Previously the baseline was incorrect due to flex alignment. * Improves support for custom form-field controls by ensuring that spacing applied to MDC inputs, also applies to custom controls. * The same will be needed for the outline appearance, but unfortunately we cannot apply any spacing to the infix until we find a solution for: material-components/material-components-web#5326
Hi @devversion, I'd like to take another look at this issue now that I understand what Angular is doing with MDC a little better. The tl;dr is that we probably won't support using the label outside of the notched outline anytime soon. It breaks a few critical things, such as the default width gap in the notch of the outline (which is important for SSR to avoid a FOUC). However, I'm not entirely unconvinced that what you're wanting cannot be achieved. You need the label to be relative the infix container for the filled text field variant, but I do not believe you need it for the outlined variant. Take a look at how the spec describes leading icons for the two: The label is displaced in the filled variant, but not the outlined variant. I would argue that any arbitrary leading content in an outlined text field would also not displace the label. With that assumption, it's no longer necessary to have a notched label inside the infix container. The downside is that you'll need one more What do you think? |
…stom controls better (angular#18161) * Fixes the baseline of form-field controls and their inputs. Previously the baseline was incorrect due to flex alignment. * Improves support for custom form-field controls by ensuring that spacing applied to MDC inputs, also applies to custom controls. * The same will be needed for the outline appearance, but unfortunately we cannot apply any spacing to the infix until we find a solution for: material-components/material-components-web#5326
@asyncLiz Thanks for looking into this. I think that you are right in saying that for the outline appearance, the label doesn't need to be displaced if the floating label is active. Though, what happens if there is no content inside the text-field and the text-field is not focused? In those cases, the label still needs to be relative to the infix container, as otherwise the label would overlap the leading icon/prefix. MDC doesn't have this issue since they known that the prefix/icon has a fixed width. Due to this limitation, my proposal was to always have the label relative to the infix container, while the outline wraps the prefix, input and suffix elements. I think the issue we are facing here is somewhat special. Ideally, we'd not allow arbitrary prefix/suffix content, but just have fixed sizes as in MDC. This isn't an option for us right now due to backwards compatibility. In the future, we should definitely get rid of this. Regarding SSR: why is that? Couldn't the default width gap be still determined? The reference to the label still exists. Just the CSS selectors which should apply to the floating label need to be adjusted. I will experiment more with this. In general, it feels more like something we need to address on our side since it's an issue specific to our old implementation of the text-field. |
@asyncLiz I experimented more with this and found a reasonable solution. We completely follow what MDC does, but instead of assuming a fixed width for the prefix container, we determine the prefix width programmatically and update the floating label horizontal position. So basically we are doing the same thing MDC does, but just use a dynamic width for the prefix. Does that sound reasonable to you? |
Ideally we'd want to not have to do that calculation programmatically, but I think I agree that it is a decent workaround with arbitrary unknown-width prefix content. Especially since we agree that it isn't the long-term solution we want. We can also place the burden on end users. If they don't want a FOUC while waiting for JS to run, they could set some sort of attribute or property that defines the width of their prefix content. Do you have any use cases or examples of dynamic prefix content? It would be good to get an idea of what people are using it for so we can bring it back to design for guidance. |
Yeah, it definitely sounds ideal to avoid the programmatic calculation at all. Do you know how it works currently for the notched-outline? i.e. how can it determine the label width on the server? I don't know of any good examples of dynamic prefix content. I just know that we need to support it for backwards compatibility, and that the prefix container width is not guaranteed to be always the same. e.g. someone could provide prefixes for a phone number, different icons, or a prefix for a serial number. |
It works because the label element is a child of the As the width of the label increases, the width of its parent notch increases. I do think one important distinction needs to be made: arbitrary leading content vs true prefixes. A true prefix (for example, "+1" in front of a phone number, or "$" in front of a monetary input) is text only and should be part of the #infixContainer in your diagram, not the #prefix container. Prefixes are aligned with the floating label for filled text fields. They do not change the floating label's horizontal position. Arbitrary leading content would include things such as leading icons. They do move the horizontal position of a filled variant's label and the outlined variant's unfocused label. Those should be part of the #prefix container in your diagram. I think it's critical that this distinction be made in the API instead of putting prefix and leading content together in the same container. This example, taken from https://material.angular.io/components/form-field/overview, would be an incorrect way of using a prefix and suffix. The prefix is not aligned under the floating label, and both the prefix and suffix are not using the correct secondary color to distinguish them from the input's color. It may be necessary to introduce a new ng-content selector for this distinction. For example: <mat-form-field>
<i matPrefix class="custom-icon"></i>
<span matPrefixText>$</span>
<input matInput placeholder="Amount" type="number">
<span matSuffixText>.00</span>
</mat-form-field> You could keep |
@asyncLiz I see. The only thing that confuses me is that the notched-outline requires us to pass an explicit width for the notch. Obviously it can just rely on the content of the notch (i.e. the label). This mostly unrelated to this whole issue, but do you know what the reason for this is?
Yes. I totally agree. We chatted about this in our team meeting, and it sounded like we can made this distinction once MDC provides support for this (based on the design doc that you wrote). Using selectors like
Yeah it looks like we'd need to do something like that to make our "unknown" prefix width work with SSR. It's unfortunate that we need to do the measurements, but I don't think there is any other way. Edit: I got it working in SSR by temporarily rendering the label inside the infix on the server if it's docked. This makes it seem as if the prefix width has been properly measured. |
You shouldn't have to provide an explicit width for the notch. It should use the width of its content by default, and when it's upgraded with JS it'll calculate a more precise spec-compliant width and set that in a style attribute. I was doing a lot of thinking about this last night and trying to come up with ways that it could work. Your idea of rendering it inside Before JS <label class="mdc-text-field">
<i class="material-icons mdc-text-field__icon mdc-text-field__icon--leading">event</i>
<div class="mdc-text-field__infix">
<input class="mdc-text-field__input" aria-labelledby="label1">
<span class="mdc-floating-label" id="label1">Label</span>
</div>
<div class="mdc-notched-outline">
<div class="mdc-notched-outline__leading"></div>
<div class="mdc-notched-outline__notch">
<span class="mdc-floating-label" aria-hidden="true" style="opacity: 0" id="label2">Label</span>
</div>
<div class="mdc-notched-outline__trailing"></div>
</div>
</label> After JS <label class="mdc-text-field">
<i class="material-icons mdc-text-field__icon mdc-text-field__icon--leading">event</i>
<div class="mdc-text-field__infix">
<input class="mdc-text-field__input" aria-labelledby="label2">
<span class="mdc-floating-label" id="label1" aria-hidden="true" style="opacity: 0">Label</span>
</div>
<div class="mdc-notched-outline">
<div class="mdc-notched-outline__leading"></div>
<div class="mdc-notched-outline__notch">
<span class="mdc-floating-label" style="left: 36px;" id="label2">Label</span>
</div>
<div class="mdc-notched-outline__trailing"></div>
</div>
</label> It's a bit messier because we need a duplicate DOM element. I'll bring it up with my team today to get their opinions. |
I guess my question is not necessarily related to this issue, but why is the JS measurement helping with being more spec-compliant? I'm trying to reason about it since it requires us to update the notch whenever the label text changes.
Thanks for helping with that. Glad that you came up with the same solution. In our case, we just render the infix label on the server, and in the browser we render the non-infix one. In Angular, this doesn't really result in a lot of code mess (fortunately), and also shouldn't have any performance implications. |
I'm going to close this issue for now. I think we've come up with a valid workaround offline and using the suggestions above. It's unlikely that the workaround will be implemented into MDC since we do not support arbitrary prefix content, but it should work for Angular. |
Currently the floating label always needs to be wrapped inside of the
notched-outline
structure. e.g.The use case of allowing that the notched-outline is decoupled from the floating label structure-wise is that prefixes and suffixes can have flexible dimensions. To make the outline work properly with flexible prefixes and suffixes, the following things are necessary:
Doing these things allows for flexible prefix and suffix containers (which is a requirement for our MDC-based implementation of the Angular Material form-field).
The problem currently is that we can only do (1) while (2) is not possible when (1) is solved. This is because the floating label cannot be a child of the notched-outline as it would mean that the label is no longer relative to the input container. Both actions/requirements are mutual exclusive at the time of writing.
To make this work the best would be if the notched-outline does not need the label as children, but rather can just accept it through a foundation/adapter method.
The text was updated successfully, but these errors were encountered: