csstailwind-csstextarea

Why a textarea is 1-line on desktop and 2-line on iOS (mobile)?


I'm working on a chatbot (as a newbie) and work on UI (using Tailwindcss).
For a reason I understand (different behaviors), I do not know how to handle it. Any clue? Thanks.

On desktop textarea is 1 row (perfect!)

enter image description here

But on mobile (iOS), it looks like this ("two" lines):

enter image description here

My code is:

<body>
    <footer
      class="fixed bottom-0 left-1/2 w-full max-w-4xl -translate-x-1/2 transform bg-white shadow-[0_0_40px_40px_rgba(255,255,255,1)]"
    >
      <div
        class="mx-6 mb-6 flex h-fit flex-none items-center justify-between gap-x-2 rounded-lg border border-gray-200 bg-white py-3 pr-2 pl-4 shadow-sm"
      >
        <textarea
          class="min-h-[24px] max-h-[240px] field-sizing-content flex-1 resize-none border-none text-base outline-0 placeholder:text-gray-400"
          id="prompt__input"
          type="text"
          name="message"
          placeholder="Comment puis-je vous aider ?"
        ></textarea>
        <button
          class="h-8 cursor-pointer px-3 text-xl font-black hover:rounded-lg hover:bg-gray-100 disabled:cursor-progress disabled:border-stone-200 disabled:text-stone-400"
          id="prompt__submit"
          type="button"
        >
          <svg
            class="fill-gray-600"
            aria-hidden="true"
            focusable="false"
            viewBox="0 0 16 16"
            width="22"
            height="22"
          >
            <path
              d="M.989 8 .064 2.68a1.342 1.342 0 0 1 1.85-1.462l13.402 5.744a1.13 1.13 0 0 1 0 2.076L1.913 14.782a1.343 1.343 0 0 1-1.85-1.463L.99 8Zm.603-5.288L2.38 7.25h4.87a.75.75 0 0 1 0 1.5H2.38l-.788 4.538L13.929 8Z"
            ></path>
          </svg>
        </button>
      </div>
    </footer>
</body>

Solution

  • Limited availability for field-sizing

    It is not available on either Firefox or Safari, so you need to look for an alternative solution.

    field-sizing utilities are not available in v3

    Note: The field-sizing utilities was introduced in TailwindCSS v4. If you still want to use it with v3, you'll need to create your own custom class. (See more: PR #14469)

    .field-sizing-content {
      field-sizing: content;
    }
    .field-sizing-fixed {
      field-sizing: fixed;
    }
    
    const plugin = require('tailwindcss/plugin')
    
    module.exports = {
      plugins: [
        plugin(function({ addUtilities }) {
          addUtilities({
            '.field-sizing-content' {
              'field-sizing': 'content';
            },
            '.field-sizing-fixed': {
              'field-sizing': 'fixed',
            },
          })
        })
      ]
    }
    

    Alternative: update height manually

    Actually, I just inserted the original field-sizing solution and my new solution so that the results can be compared.

    For the alternative solution, I set up a function on the textarea's input event that automatically adjusts the textarea's height to its scrollHeight, ensuring that the text will always be fully visible, with the max-h-[240px] acting as the constraint.

    To ensure it works properly, the rows="1" setting is required to start with a single row by default, and an auto height setting is needed so that the scrollHeight actually starts decreasing when the content is deleted.

    document.addEventListener("DOMContentLoaded", function () {
      const textarea = document.getElementById("prompt__input__alternative");
      
      // Update height to scrollHeight
      function updateHeight() {
        textarea.style.height = `auto`; /* for can reset height */
        textarea.style.height = `${textarea.scrollHeight}px`;
      }
    
      textarea.addEventListener("input", updateHeight);
      updateHeight();
    });
    <script src="https://unpkg.com/@tailwindcss/browser@4"></script>
    
    <footer
      class="fixed bottom-0 left-1/2 w-full max-w-4xl -translate-x-1/2 transform bg-white shadow-[0_0_40px_40px_rgba(255,255,255,1)]"
    >
      <p>Original with field-sizing-content</p>
      <div
        class="mx-6 mb-6 flex h-fit flex-none items-center justify-between gap-x-2 rounded-lg border border-gray-200 bg-white py-3 pr-2 pl-4 shadow-sm"
      >
        <textarea
          class="min-h-[24px] max-h-[240px] field-sizing-content flex-1 resize-none border-none text-base outline-0 placeholder:text-gray-400"
          id="prompt__input"
          type="text"
          name="message"
          placeholder="Comment puis-je vous aider ?"
        ></textarea>
        <button
          class="h-8 cursor-pointer px-3 text-xl font-black hover:rounded-lg hover:bg-gray-100 disabled:cursor-progress disabled:border-stone-200 disabled:text-stone-400"
          id="prompt__submit"
          type="button"
        >
          <svg
            class="fill-gray-600"
            aria-hidden="true"
            focusable="false"
            viewBox="0 0 16 16"
            width="22"
            height="22"
          >
            <path
              d="M.989 8 .064 2.68a1.342 1.342 0 0 1 1.85-1.462l13.402 5.744a1.13 1.13 0 0 1 0 2.076L1.913 14.782a1.343 1.343 0 0 1-1.85-1.463L.99 8Zm.603-5.288L2.38 7.25h4.87a.75.75 0 0 1 0 1.5H2.38l-.788 4.538L13.929 8Z"
            ></path>
          </svg>
        </button>
      </div>
    
      <p>Alternative with JavaScript</p>
      <div
        class="mx-6 mb-6 flex h-fit flex-none items-center justify-between gap-x-2 rounded-lg border border-gray-200 bg-white py-3 pr-2 pl-4 shadow-sm"
      >
        <textarea
          class="w-full min-h-[24px] max-h-[240px] h-auto resize-none border-none text-base outline-0 placeholder:text-gray-400"
          id="prompt__input__alternative"
          type="text"
          name="message"
          placeholder="Comment puis-je vous aider ?"
          rows="1"
        ></textarea>
        <button
          class="h-8 cursor-pointer px-3 text-xl font-black hover:rounded-lg hover:bg-gray-100 disabled:cursor-progress disabled:border-stone-200 disabled:text-stone-400"
          id="prompt__submit"
          type="button"
        >
          <svg
            class="fill-gray-600"
            aria-hidden="true"
            focusable="false"
            viewBox="0 0 16 16"
            width="22"
            height="22"
          >
            <path
              d="M.989 8 .064 2.68a1.342 1.342 0 0 1 1.85-1.462l13.402 5.744a1.13 1.13 0 0 1 0 2.076L1.913 14.782a1.343 1.343 0 0 1-1.85-1.463L.99 8Zm.603-5.288L2.38 7.25h4.87a.75.75 0 0 1 0 1.5H2.38l-.788 4.538L13.929 8Z"
            ></path>
          </svg>
        </button>
      </div>
    </footer>

    enter image description here enter image description here enter image description here

    Alternative solution with contenteditable element

    Actually, I just inserted the original field-sizing solution and my new solution so that the results can be compared.

    The alternative solution works here even without JavaScript. The JavaScript is needed to hide and show the placeholder, and for that, I had to listen for the input event on the contenteditable div.

    document.addEventListener("DOMContentLoaded", function () {
      const contentEditableDiv = document.getElementById("prompt__input__alternative");
      const placeholderSpan = document.getElementById("primpt__input__alternative__placeholder");
    
      // Hide placeholder when input length > 0
      function togglePlaceholder() {
        if (contentEditableDiv.textContent.trim().length > 0) {
          placeholderSpan.style.display = "none";
        } else {
          placeholderSpan.style.display = "inline";
        }
      }
    
      contentEditableDiv.addEventListener("input", togglePlaceholder);
      togglePlaceholder();
    });
    <script src="https://unpkg.com/@tailwindcss/browser@4"></script>
    
    <footer
      class="fixed bottom-0 left-1/2 w-full max-w-4xl -translate-x-1/2 transform bg-white shadow-[0_0_40px_40px_rgba(255,255,255,1)]"
    >
      <p>Original with field-sizing-content</p>
      <div
        class="mx-6 mb-6 flex h-fit flex-none items-center justify-between gap-x-2 rounded-lg border border-gray-200 bg-white py-3 pr-2 pl-4 shadow-sm"
      >
        <textarea
          class="min-h-[24px] max-h-[240px] field-sizing-content flex-1 resize-none border-none text-base outline-0 placeholder:text-gray-400"
          id="prompt__input"
          type="text"
          name="message"
          placeholder="Comment puis-je vous aider ?"
        ></textarea>
        <button
          class="h-8 cursor-pointer px-3 text-xl font-black hover:rounded-lg hover:bg-gray-100 disabled:cursor-progress disabled:border-stone-200 disabled:text-stone-400"
          id="prompt__submit"
          type="button"
        >
          <svg
            class="fill-gray-600"
            aria-hidden="true"
            focusable="false"
            viewBox="0 0 16 16"
            width="22"
            height="22"
          >
            <path
              d="M.989 8 .064 2.68a1.342 1.342 0 0 1 1.85-1.462l13.402 5.744a1.13 1.13 0 0 1 0 2.076L1.913 14.782a1.343 1.343 0 0 1-1.85-1.463L.99 8Zm.603-5.288L2.38 7.25h4.87a.75.75 0 0 1 0 1.5H2.38l-.788 4.538L13.929 8Z"
            ></path>
          </svg>
        </button>
      </div>
    
      <p>Alternative with contenteditable</p>
      <div
        class="mx-6 mb-6 flex h-fit flex-none items-center justify-between gap-x-2 rounded-lg border border-gray-200 bg-white py-3 pr-2 pl-4 shadow-sm"
      >
        <div class="relative w-full min-h-[24px] max-h-[240px] overflow-auto">
          <span id="primpt__input__alternative__placeholder" class="w-full text-gray-400 absolute top-0 left-0 z-0">
            Comment puis-je vous aider ?
          </span>
          <div
            contenteditable="true"
            class="relative z-10 w-full min-h-[24px] max-h-[240px] border-none text-base outline-0"
            id="prompt__input__alternative"
          ></div>
        </div>
        <button
          class="h-8 cursor-pointer px-3 text-xl font-black hover:rounded-lg hover:bg-gray-100 disabled:cursor-progress disabled:border-stone-200 disabled:text-stone-400"
          id="prompt__submit"
          type="button"
        >
          <svg
            class="fill-gray-600"
            aria-hidden="true"
            focusable="false"
            viewBox="0 0 16 16"
            width="22"
            height="22"
          >
            <path
              d="M.989 8 .064 2.68a1.342 1.342 0 0 1 1.85-1.462l13.402 5.744a1.13 1.13 0 0 1 0 2.076L1.913 14.782a1.343 1.343 0 0 1-1.85-1.463L.99 8Zm.603-5.288L2.38 7.25h4.87a.75.75 0 0 1 0 1.5H2.38l-.788 4.538L13.929 8Z"
            ></path>
          </svg>
        </button>
      </div>
    </footer>