Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow <textarea> to size to its contents like <div contenteditable> #6807

Closed
randfur opened this issue Jun 26, 2021 · 24 comments
Closed

Allow <textarea> to size to its contents like <div contenteditable> #6807

randfur opened this issue Jun 26, 2021 · 24 comments
Labels
addition/proposal New features or enhancements needs implementer interest Moving the issue forward requires implementers to express interest topic: editing topic: forms topic: rendering

Comments

@randfur
Copy link

randfur commented Jun 26, 2021

There doesn't seem to be a non-JS way of accepting plantext in an element that resizes to fit the text (like <div> does).
https://css-tricks.com/auto-growing-inputs-textareas/

Could a layout mode be added to textarea to make it behave like <div>?

@randfur randfur changed the title Allow <textarea> to size it its contents like <div contenteditable> Allow <textarea> to size to its contents like <div contenteditable> Jun 26, 2021
@rniwa
Copy link

rniwa commented Jun 26, 2021

There is non-standard contenteditable=plaintext-only. Maybe we should make it official.

@prlbr
Copy link

prlbr commented Apr 11, 2022

There is non-standard contenteditable=plaintext-only. Maybe we should make it official.

A <div contenteditable=plaintext-only></div> would not participate in form submission though, would it? I would love to have an automatically resizing <textarea> as proposed by @randfur whose content is sent when the form is submitted.

@annevk annevk added topic: rendering needs implementer interest Moving the issue forward requires implementers to express interest labels Apr 22, 2022
@annevk
Copy link
Member

annevk commented Apr 22, 2022

That's an interesting idea. I wonder if @whatwg/css thought about automatically resizing textarea at some point. Perhaps some aspects could be redefined such that min-content and max-content would become useful?

@bfgeek
Copy link
Member

bfgeek commented May 2, 2022

We've been looking at this problem a little - I wrote up an explainer for an approach we think might work:

Expanding <textarea> explainer

A common request from web-developers is to allow the <textarea> element to expand based on its contents.
There are many libraries/patterns to emulate this behaviour, e.g.

These libraries are all pretty good! They are at a tiny performance disadvantage to doing this natively in the browser but not by much.

A concrete proposal

<textarea rows="auto" minrows="3" maxrows="5">

textarea-1

<textarea rows="auto" minrows="3">

textarea-2

interface HTMLTextAreaElement : HTMLElement {
  [CEReactions] attribute unsigned long? rows;
  [CEReactions] attribute unsigned long? minRows;
  [CEReactions] attribute unsigned long? maxRows;

The web developer would explicitly opt-in to this mode via. the rows="auto" attribute. By default in all UAs implicitly have rows="2". The HTMLTextAreaElement interface would return null whenn rows="auto" is set.

Similarly the minrows & maxrows attributes accept a non-zero integer, and by default are null.

Implementations would could how many lines are present in the textarea, and apply the following logic:

unsigned intrinsic_line_count = /* count how many lines, with a minimum of 1. */;
const auto* text_area_element = ...;

unsigned line_count = intrinsic_line_count; 
if (text_area_element.rows().has_value())
  line_count = text_area_element.rows().get_value();
if (text_area_element.max_rows().has_value())
  line_count = std::min(line_count, text_area_element.max_rows().get_value());
if (text_area_element.min_rows().has_value())
  line_count = std::max(line_count, text_area_element.min_rows().get_value());

This min/max clamping logic is exactly the same as the logic within CSS, and specifically is how the clamp() function works in CSS.

Similar to today the intrinsic block-size of the textarea would take this line-count then multiply it with this line-height computed based on the primary font. (It is important we don't do this based on the content, as the textarea might be slightly different sizes depending on if it has content or not).

Similar to rows="N" today this would become the intrinsic block-size of the <textarea>. In CSS (roughly speaking) min-content, and max-content would compute to this value.

This would also be the weakest constraint (similar to the behaviour in implementations already). E.g. setting as explicit block-size would work as expected, as well as setting min-block-size, max-block-size constraints.

Placeholder behaviour

textarea-placeholder

The placeholder doesn't contribute to the line-counting behaviour above. Why? TL;DR it seems good, but the behaviour is actually quirky/non-intuitive, and its mostly a non-issue anyway.

If you imagine something like:
<textarea minrows="2" rows="auto" placeholder="something that will be three lines">

The proposal as described will be two lines, with scrollable overflow to the third placeholder line.

An alternative is to make it three lines to encompass the placeholder, however if you do that, when you focus the <textarea> it'll jump down to two lines, creating a jarring experience.

The next alternative is to count both the placeholder, and textarea content in the line-count implementation. The implementation for browers gets more difficult at this stage, as engines will explicitly remove the placeholder upon focus, and therefore have nothing to measure.

Additionally things get quirky if the textarea is resized. E.g. if you have content in the textarea, resize the textarea to be smaller in the inline-axis, the placeholder may have more lines than the content, and the textarea will be larger that you expect.

Finally this is mostly a non-issue. The polyfills etc haven't considered this case in-depth, and have lots of different behaviour here. Most placeholders are short, and single line. Even with languages that expand significantly upon translation still should fit as developers expect, (and will still be accessible with scroll).

Alternatives considered

No clamping except when rows="auto"?

In the above logic, we always apply the clamping logic, even to an explicit row count. E.g.
<textarea minrows="4" rows="2">
The above example would always have 4 rows.

We could alternatively only apply the clamping logic if rows="auto" was present. Folks that I've shown this to so far don't have a strong opinion one way or the other. The current proposal is marginally easier to implement, but happy for it to go either way.

Microsyntax for rows attribute instead?

E.g. one could imagine something like: rows="minmax(2, 4)". Personally this seemed like too much complexity, and more difficult to remember that individual attributes on the textarea.

Implicit opt-in to rows="auto"?

E.g. <textarea minrows="2" maxrows="4"> without the need to specifiy rows="auto". Initially this is what I had (as soon as you set either minrows/maxrows this rows attribute would be treated as null). However all the people I showed this design to initially preferred the explicit opt-in to this behaviour.

"auto" keyword?

"auto" could be a poor keyword, "dynamic" / "expand" / "content"?

Why not on cols as well?

TL;DR cols is different. cols works by measuring a glyph in the font, and really only works well for monospaced fonts.
I haven't seen any web developers trying to emulate this behaviour for cols.

No shrinking when removing lines?

No. The current proposal (and basically every example I've seen) will shrink the textarea as you remove lines. One could argue that this shouldn't happen, but I've seen no examples of real world applications using this model. Can easily add this option later, but lets not do this until someone asks for it.

A new keyword/function in CSS?

Could work, but more complexity that is really needed. As this logic needs to work on lines, you'd need something like:

textarea { height: min-max-line-height-based-on-line-count(2, 4); }

There is an argument for add CSS properties, then the rows/minrows/maxrows become presentational hints mapping to actual CSS properties, e.g. textarea-rows/textarea-min-rows/etc.

@tabatkins
Copy link
Contributor

There is an argument for add CSS properties, then the rows/minrows/maxrows become presentational hints mapping to actual CSS properties, e.g. textarea-rows/textarea-min-rows/etc.

A little more detail, since I argued for this in person:

Whether a textarea is suitable for auto-expansion or not can depend on how it's used in the UI, which can change based on screen size, etc. This is similar to how something that might be tabs on desktop should be accordion on mobile (and thus, the choice of which is used shouldn't be baked into the markup, but rather be controllable via CSS); it's 100% a layout/styling choice rather than a semantic one, and so should be controllable via CSS (rather than possibly requiring an author who does want it to change based on MQs to set up MQ listeners to manually toggle the attributes in script...). And beyond the raw "can it expand or not", the min/max lines it should be able to expand to is clearly a stylistic choice that can vary based on the surrounding layout context.

Secondly, if you have multiple such textareas, there's a good chance you might want them to all work the same way. One style rule is easier than adding attributes to each by hand.

So yeah, having these as HTML attributes is good, but they should be presentational hints for a new trio of textarea-specific CSS properties that actually control this functionality. (And I'd be happy to help champion that over in the CSSWG; it probably belongs in the CSS UI spec.)

@annevk
Copy link
Member

annevk commented May 3, 2022

cols has semantic implications, but it indeed seems that rows does not. For some reason rows was not deprecated however. Perhaps because it did not have a suitable CSS alternative?

Is the complexity with a CSS-based solution that it has to work across all elements?

It's not immediately clear to me we want to introduce new presentational attributes.

@tabatkins
Copy link
Contributor

Is the complexity with a CSS-based solution that it has to work across all elements?

No, it doesn't. While we generally try to define things such that they work across a broad range of elements, we do have element-specific properties (a bunch inherited from SVG, mostly). An explicit textarea-rows property is a little weird but not unprecedented, and unproblematic mechanically.

It's not immediately clear to me we want to introduce new presentational attributes.

Well, at least rows would become presentational, and I don't think it's unreasonable to have some consistency there.

@annevk
Copy link
Member

annevk commented May 9, 2022

I guess I'd argue that rows should not be allowed anymore and you'd use this new property instead.

@tkent-google
Copy link
Contributor

CSSWG resolution:
w3c/csswg-drafts#7542 (comment)

provisionally form-sizing: normal | auto

I think css-ui should have its property definition and a high-level overview, and the HTML specification should define concrete behaviors of each HTML elements.

We can start with textarea, then can expand support to other elements.

@tkent-google
Copy link
Contributor

I made a prototype for <textarea>, and my current thoughts are:

The content box should include the height of the last empty line even if form-sizing: normal

It's same as contenteditable=true.
<textarea style="form-sizing:normal"></textarea> should have one line height.

<textarea style="form-sizing:normal">
foo
</textarea>

It should have two lines height though the following <pre> has one line height.

<pre>
foo
</pre>

WIthout this behavior, a text caret can be hidden, and web authors can't enlarge the box for it without JavaScript.

The content box should be union of a placeholder text and a text caret.

<style>
textarea {
  form-sizing: normal;
  font-size: 32px;
}
textarea::placeholder {
  font-size: 12px;
}
</style>
<textarea placeholder="foo"></textarea>

The width of the <textarea> should be the width of the placeholder.
The height of the <textarea> should be one line height for font-size: 32px.

@tkent-google
Copy link
Contributor

Google Chrome 119.0.6022.0 canary has an experimental implementation of form-sizing property for <textarea> and text-field <input>. You can try it by enabling chrome://flags/#enable-experimental-web-platform-features.

  • rows cols size attributes are ignored if form-sizing: normal.
  • Behavior with placeholder might look tricky.

Your feedbacks is welcome.

@tkent-google
Copy link
Contributor

I'm making an HTML specification patch. My current thought is:

  • input element as a text entry widget
    size attribute is ignored if field-sizing: content
  • input element as domain-specific widgets
    field-sizing support is optional.
  • input element as a file upload control
    Ditto.
  • select element
    size attribute is used only for dropdown/listbox switching if
    field-sizing: content
  • textarea element
    cols and rows are ignored if field-sizing: content

tkent-google added a commit to tkent-google/html that referenced this issue Oct 30, 2023
This covers:
 - input element as a text entry widget
    size attribute is ignored if field-sizing:content
 - input element as domain-specific widgets (optional)
 - input element as a file upload control (optional)
 - select element
    size attribute is used only for dropdown/listbox switching if
    field-sizing:content
 - textarea element
    cols/rows are ignored if field-sizing:content

Issue: whatwg#6807
Issue: w3c/csswg-drafts#7542
@domenic
Copy link
Member

domenic commented Oct 30, 2023

Is there any interaction with appearance? /cc @zcorpan

  • field-sizing support is optional.

Is there a use case for this? Maybe we should just not support it, to avoid having potential interop issues?

@annevk
Copy link
Member

annevk commented Oct 30, 2023

Presumably <textarea cols> is only ignored for determining width, but not for inserting line breaks?

@bfgeek
Copy link
Member

bfgeek commented Oct 30, 2023

Presumably <textarea cols> is only ignored for determining width, but not for inserting line breaks?

Can you elaborate what you mean by this? The cols attribute doesn't affect line-breaking - it is just an input to the default intrinsic sizing algorithm for textarea elements. E.g.

<textarea cols=1 style="width: 100px">

@annevk
Copy link
Member

annevk commented Oct 30, 2023

It doesn't in WebKit (and maybe not in Chromium therefore), but per the HTML Standard that's a bug: https://html.spec.whatwg.org/#textarea-wrapping-transformation.

@bfgeek
Copy link
Member

bfgeek commented Oct 30, 2023

It doesn't appear to do anything in Firefox either? cc/ @emilio @dholbert in case I'm missing something?

@emilio
Copy link
Contributor

emilio commented Oct 30, 2023

Yeah, same for us, see here

@bfgeek
Copy link
Member

bfgeek commented Oct 30, 2023

I filed a separate issue about the spec not reflecting reality here: #9896

@tkent-google
Copy link
Contributor

Is there any interaction with appearance? /cc @zcorpan

I don't think so.

  • field-sizing support is optional.

Is there a use case for this? Maybe we should just not support it, to avoid having potential interop issues?

field-sizing would be helpful for <input type=number>, which major browsers implement it as a text entry widget.
I don't think it's helpful for temporal input types.
So, let's make it mandatory for type=number, and no support for other types.

As for <input type=file>, it's helpful to avoid ellipsizing file names.
The current specification doesn't mention fixed-width behavior like other input types. So I'm not sure if it's safe to ask field-sizing support.

tkent-google added a commit to tkent-google/html that referenced this issue Nov 2, 2023
This covers:
 - input element as a text entry widget
    size attribute is ignored if field-sizing:content
 - input element as domain-specific widgets (optional)
 - input element as a file upload control (optional)
 - select element
    size attribute is used only for dropdown/listbox switching if
    field-sizing:content
 - textarea element
    cols/rows are ignored if field-sizing:content

Issue: whatwg#6807
Issue: w3c/csswg-drafts#7542
@zcorpan
Copy link
Member

zcorpan commented Nov 6, 2023

It seems to me block-size for textarea is the most common use case. How much demand is there for the other things?

Also see @emilio's concerns with autofill in #9903 (comment)

@bfgeek
Copy link
Member

bfgeek commented Nov 6, 2023

It seems to me block-size for textarea is the most common use case. How much demand is there for the other things?

There is demand for the other things (designers wanting to shrink-wrap controls quite often).

tkent-google added a commit to web-platform-tests/wpt that referenced this issue Feb 1, 2024
This includes tests to confirm size/cols/rows are not presentational hints.

Issue: whatwg/html#6807
@domenic domenic closed this as completed in ae80157 Feb 6, 2024
tkent-google added a commit to web-platform-tests/wpt that referenced this issue Feb 6, 2024
This includes tests to confirm size/cols/rows are not presentational hints.

Issue: whatwg/html#6807
moz-v2v-gh pushed a commit to mozilla/gecko-dev that referenced this issue Feb 13, 2024
Automatic update from web-platform-tests
html: Tests for field-sizing (#44346)

This includes tests to confirm size/cols/rows are not presentational hints.

Issue: whatwg/html#6807
--

wpt-commits: df6595ec7e75fdf8fb524a039c32a030fc1075e9
wpt-pr: 44346
jamienicol pushed a commit to jamienicol/gecko that referenced this issue Feb 15, 2024
Automatic update from web-platform-tests
html: Tests for field-sizing (#44346)

This includes tests to confirm size/cols/rows are not presentational hints.

Issue: whatwg/html#6807
--

wpt-commits: df6595ec7e75fdf8fb524a039c32a030fc1075e9
wpt-pr: 44346
gecko-dev-updater pushed a commit to marco-c/gecko-dev-wordified that referenced this issue Feb 16, 2024
Automatic update from web-platform-tests
html: Tests for field-sizing (#44346)

This includes tests to confirm size/cols/rows are not presentational hints.

Issue: whatwg/html#6807
--

wpt-commits: df6595ec7e75fdf8fb524a039c32a030fc1075e9
wpt-pr: 44346

UltraBlame original commit: 8e4feaecb790a7e698dd0c2e84cd6d8386c6b13b
mbrodesser-Igalia pushed a commit to mbrodesser-Igalia/wpt that referenced this issue Feb 19, 2024
This includes tests to confirm size/cols/rows are not presentational hints.

Issue: whatwg/html#6807
gecko-dev-updater pushed a commit to marco-c/gecko-dev-comments-removed that referenced this issue Feb 20, 2024
Automatic update from web-platform-tests
html: Tests for field-sizing (#44346)

This includes tests to confirm size/cols/rows are not presentational hints.

Issue: whatwg/html#6807
--

wpt-commits: df6595ec7e75fdf8fb524a039c32a030fc1075e9
wpt-pr: 44346

UltraBlame original commit: 8e4feaecb790a7e698dd0c2e84cd6d8386c6b13b
marcoscaceres pushed a commit to web-platform-tests/wpt that referenced this issue Feb 23, 2024
This includes tests to confirm size/cols/rows are not presentational hints.

Issue: whatwg/html#6807
@qasim-dzinemedia
Copy link

There is non-standard contenteditable=plaintext-only. Maybe we should make it official.

plaintext-only would work smoothly on Chrome, but in Firefox or older browsers, the div might be disabled. The only solution to address this issue is by implementing JavaScript.

This code worked for me
const editableDiv = document.getElementById('editableDiv');

    editableDiv.addEventListener('paste', (event) => {
        event.preventDefault();
        const text = (event.clipboardData || window.clipboardData).getData('text/plain');
        document.execCommand('insertText', false, text);
    });

    editableDiv.addEventListener('input', () => {
        // Remove any non-plaintext content (e.g., images, formatted text)
        editableDiv.innerHTML = editableDiv.innerText;
    });

@mangelozzi
Copy link

mangelozzi commented Aug 27, 2024

I'm making an HTML specification patch. My current thought is:

  • input element as a text entry widget
    size attribute is ignored if field-sizing: content
  • input element as domain-specific widgets
    field-sizing support is optional.
  • input element as a file upload control
    Ditto.
  • select element
    size attribute is used only for dropdown/listbox switching if
    field-sizing: content
  • textarea element
    cols and rows are ignored if field-sizing: content

Well done for implementing it, it is so nice to cut out of the resize observers and JS we to have to do this. Good Job!

Would have been great to treat cols and rows like min-width and min-height. Then one could say like rows="2" and set field-sizing: content to have a textarea that is at least 2 lines, but grows as needed. At the moment one has to type text in a textbox to see how big the text area is a n rows by inspecting in the dev tools, get the min-height, use that, but is prone to breaking when font family or font size changes.

The bfgeek's proposal was superior because one could specify how many rows to have at least, and then specify it should grow as required. Which I suspect in real website is the most common use case.

@whatwg whatwg deleted a comment from RIGHTHOOD Aug 27, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
addition/proposal New features or enhancements needs implementer interest Moving the issue forward requires implementers to express interest topic: editing topic: forms topic: rendering
Development

No branches or pull requests