Skip to content

Conversation

@rugoncalves
Copy link

@rugoncalves rugoncalves commented Feb 9, 2026

Issue number: resolves internal


What is the current behavior?

  • The height of the textarea would not correspond to the rows number, when it the row number was set to 1:
    image

  • Ionic theme specifics:

    • Some paddings and margins were inaccurate;
    • Some CSS selectors were being more generic than it should:
      • :host([auto-grow]) .textarea-wrapper-inner
        This selector was always being applied independently on the value of the attribute auto-grow;

What is the new behavior?

  • The min-height is now respecting the rows attribute:
    image

  • The ionic theme has the following changes:

    • .textarea-size-* classes stopped forcing the min-height;
    • textarea minimum height, is now equivalent to the number of rows plus half row.
      This will cause the last line to be partially visible;
    • Fixed selector :host([auto-grow]) .textarea-wrapper-inner, to be applied only when auto-grow = false;
    • Removed margin of the native textarea element, as the ionic theme adds padding, will make the textarea never overlaps the label;
    • Added a style inline setting up a CSS variable --host-rows in the host, so that the minimum height can be calculated in the element div[.textarea-wrapper-inner];

Does this introduce a breaking change?

  • Yes
  • No

Other information

@rugoncalves rugoncalves requested a review from a team as a code owner February 9, 2026 18:44
@vercel
Copy link

vercel bot commented Feb 9, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
ionic-framework Ready Ready Preview, Comment Feb 12, 2026 10:49am

Request Review

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates ion-textarea styling so the control’s minimum height better matches the configured rows (especially for rows="1"), with additional Ionic-theme-specific selector and spacing fixes.

Changes:

  • Add a data-attr-rows attribute to the textarea inner wrapper to enable rows-based styling.
  • Update Ionic theme sizing/min-height behavior, plus tighten auto-grow selectors to exclude auto-grow="false".
  • Adjust Ionic theme textarea top margin behavior (and remove the old outline-only margin rule).

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 10 comments.

File Description
core/src/components/textarea/textarea.tsx Adds data-attr-rows on the wrapper for CSS-based rows sizing.
core/src/components/textarea/textarea.ionic.scss Reworks Ionic theme min-height logic, auto-grow selectors, and label-placement spacing.
core/src/components/textarea/textarea.ionic.outline.scss Removes outline-only textarea margin-top rule (spacing now handled elsewhere).
core/src/components/textarea/textarea.common.scss Adds rows-related min-height override for certain host/class combinations.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

rugoncalves and others added 2 commits February 9, 2026 21:14
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@gnbm
Copy link
Contributor

gnbm commented Feb 11, 2026

Copy link
Member

@brandyscarney brandyscarney left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left some comments requesting some test changes but I will defer to @thetaPC for the functionality since she has already left comments on that. 🙂

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the icon placement after the changes right? It looks really close to the top:

next branch
next branch

From Figma:

Image

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well spotted! That's indeed a bug!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can remove the shape, fill & label placement examples from this test. The only thing we really need to check for is things that will be affected by rows which is the default textareas, size and auto-grow.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree. Accepting suggestion!

<style>
.grid {
display: grid;
grid-template-columns: repeat(3, minmax(250px, 1fr));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
grid-template-columns: repeat(3, minmax(250px, 1fr));
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));

Comment on lines +30 to +35
@media screen and (max-width: 800px) {
.grid {
grid-template-columns: 1fr;
padding: 0;
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
@media screen and (max-width: 800px) {
.grid {
grid-template-columns: 1fr;
padding: 0;
}
}

See above change that accounts for this

Comment on lines +62 to +89
test('should respect rows attribute with fill outline and solid', async ({ page }) => {
await page.setContent(
`
<div id="container" style="display: flex; flex-direction: column; gap: 20px;">
<ion-textarea
rows="4"
fill="outline"
label="Outline"
label-placement="stacked"
helper-text="rows=4, fill=outline, label-placement=stacked"
value="1&#10;2&#10;3&#10;4&#10;5&#10;6&#10;7&#10;8&#10;9&#10;0"
></ion-textarea>
<ion-textarea
rows="4"
fill="solid"
label="Solid"
label-placement="stacked"
helper-text="rows=4, fill=solid, label-placement=stacked"
value="1&#10;2&#10;3&#10;4&#10;5&#10;6&#10;7&#10;8&#10;9&#10;0"
></ion-textarea>
</div>
`,
config
);

const container = page.locator('#container');
await expect(container).toHaveScreenshot(screenshot(`textarea-rows-4-fill`));
});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need to check fill since it shouldn't modify anything related to the height.

Note: don't forget to remove screenshots

Suggested change
test('should respect rows attribute with fill outline and solid', async ({ page }) => {
await page.setContent(
`
<div id="container" style="display: flex; flex-direction: column; gap: 20px;">
<ion-textarea
rows="4"
fill="outline"
label="Outline"
label-placement="stacked"
helper-text="rows=4, fill=outline, label-placement=stacked"
value="1&#10;2&#10;3&#10;4&#10;5&#10;6&#10;7&#10;8&#10;9&#10;0"
></ion-textarea>
<ion-textarea
rows="4"
fill="solid"
label="Solid"
label-placement="stacked"
helper-text="rows=4, fill=solid, label-placement=stacked"
value="1&#10;2&#10;3&#10;4&#10;5&#10;6&#10;7&#10;8&#10;9&#10;0"
></ion-textarea>
</div>
`,
config
);
const container = page.locator('#container');
await expect(container).toHaveScreenshot(screenshot(`textarea-rows-4-fill`));
});

await expect(container).toHaveScreenshot(screenshot(`textarea-rows-different-sizes`));
});

test('should respect rows attribute with value content', async ({ page }) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How is this different from should respect rows attribute and set min-height?

Comment on lines 165 to 256
test('should respect rows attribute with different label placements', async ({ page }) => {
await page.setContent(
`
<div id="container" style="display: flex; flex-direction: column; gap: 20px;">
<ion-textarea
rows="3"
fill="outline"
label="Start"
label-placement="start"
helper-text="rows=3, fill=outline, label-placement=start"
value="1&#10;2&#10;3&#10;4&#10;5&#10;6&#10;7&#10;8&#10;9&#10;0"
></ion-textarea>
<ion-textarea
rows="3"
fill="outline"
label="End"
label-placement="end"
helper-text="rows=3, fill=outline, label-placement=end"
value="1&#10;2&#10;3&#10;4&#10;5&#10;6&#10;7&#10;8&#10;9&#10;0"
></ion-textarea>
<ion-textarea
rows="3"
fill="outline"
label="Floating"
label-placement="floating"
helper-text="rows=3, fill=outline, label-placement=floating"
value="1&#10;2&#10;3&#10;4&#10;5&#10;6&#10;7&#10;8&#10;9&#10;0"
></ion-textarea>
<ion-textarea
rows="3"
fill="outline"
label="Fixed"
label-placement="fixed"
helper-text="rows=3, fill=outline, label-placement=fixed"
value="1&#10;2&#10;3&#10;4&#10;5&#10;6&#10;7&#10;8&#10;9&#10;0"
></ion-textarea>
<ion-textarea
rows="3"
fill="outline"
label="Stacked"
label-placement="stacked"
helper-text="rows=3, fill=outline, label-placement=stacked"
value="1&#10;2&#10;3&#10;4&#10;5&#10;6&#10;7&#10;8&#10;9&#10;0"
></ion-textarea>
</div>
`,
config
);

const container = page.locator('#container');
await expect(container).toHaveScreenshot(screenshot(`textarea-rows-label-placements`));
});

test('should respect rows attribute with different shapes', async ({ page }) => {
await page.setContent(
`
<div id="container" style="display: flex; flex-direction: column; gap: 20px;">
<ion-textarea
rows="3"
shape="soft"
fill="outline"
label="Soft"
label-placement="stacked"
helper-text="rows=3, shape=soft, fill=outline, label-placement=stacked"
value="1&#10;2&#10;3&#10;4&#10;5&#10;6&#10;7&#10;8&#10;9&#10;0"
></ion-textarea>
<ion-textarea
rows="3"
shape="round"
fill="outline"
label="Round"
label-placement="stacked"
helper-text="rows=3, shape=round, fill=outline, label-placement=stacked"
value="1&#10;2&#10;3&#10;4&#10;5&#10;6&#10;7&#10;8&#10;9&#10;0"
></ion-textarea>
<ion-textarea
rows="3"
shape="rectangular"
fill="outline"
label="Rectangular"
label-placement="stacked"
helper-text="rows=3, shape=rectangular, fill=outline, label-placement=stacked"
value="1&#10;2&#10;3&#10;4&#10;5&#10;6&#10;7&#10;8&#10;9&#10;0"
></ion-textarea>
</div>
`,
config
);

const container = page.locator('#container');
await expect(container).toHaveScreenshot(screenshot(`textarea-rows-shapes`));
});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need to check these since it shouldn't modify anything related to the height.

Note: don't forget to remove screenshots

Suggested change
test('should respect rows attribute with different label placements', async ({ page }) => {
await page.setContent(
`
<div id="container" style="display: flex; flex-direction: column; gap: 20px;">
<ion-textarea
rows="3"
fill="outline"
label="Start"
label-placement="start"
helper-text="rows=3, fill=outline, label-placement=start"
value="1&#10;2&#10;3&#10;4&#10;5&#10;6&#10;7&#10;8&#10;9&#10;0"
></ion-textarea>
<ion-textarea
rows="3"
fill="outline"
label="End"
label-placement="end"
helper-text="rows=3, fill=outline, label-placement=end"
value="1&#10;2&#10;3&#10;4&#10;5&#10;6&#10;7&#10;8&#10;9&#10;0"
></ion-textarea>
<ion-textarea
rows="3"
fill="outline"
label="Floating"
label-placement="floating"
helper-text="rows=3, fill=outline, label-placement=floating"
value="1&#10;2&#10;3&#10;4&#10;5&#10;6&#10;7&#10;8&#10;9&#10;0"
></ion-textarea>
<ion-textarea
rows="3"
fill="outline"
label="Fixed"
label-placement="fixed"
helper-text="rows=3, fill=outline, label-placement=fixed"
value="1&#10;2&#10;3&#10;4&#10;5&#10;6&#10;7&#10;8&#10;9&#10;0"
></ion-textarea>
<ion-textarea
rows="3"
fill="outline"
label="Stacked"
label-placement="stacked"
helper-text="rows=3, fill=outline, label-placement=stacked"
value="1&#10;2&#10;3&#10;4&#10;5&#10;6&#10;7&#10;8&#10;9&#10;0"
></ion-textarea>
</div>
`,
config
);
const container = page.locator('#container');
await expect(container).toHaveScreenshot(screenshot(`textarea-rows-label-placements`));
});
test('should respect rows attribute with different shapes', async ({ page }) => {
await page.setContent(
`
<div id="container" style="display: flex; flex-direction: column; gap: 20px;">
<ion-textarea
rows="3"
shape="soft"
fill="outline"
label="Soft"
label-placement="stacked"
helper-text="rows=3, shape=soft, fill=outline, label-placement=stacked"
value="1&#10;2&#10;3&#10;4&#10;5&#10;6&#10;7&#10;8&#10;9&#10;0"
></ion-textarea>
<ion-textarea
rows="3"
shape="round"
fill="outline"
label="Round"
label-placement="stacked"
helper-text="rows=3, shape=round, fill=outline, label-placement=stacked"
value="1&#10;2&#10;3&#10;4&#10;5&#10;6&#10;7&#10;8&#10;9&#10;0"
></ion-textarea>
<ion-textarea
rows="3"
shape="rectangular"
fill="outline"
label="Rectangular"
label-placement="stacked"
helper-text="rows=3, shape=rectangular, fill=outline, label-placement=stacked"
value="1&#10;2&#10;3&#10;4&#10;5&#10;6&#10;7&#10;8&#10;9&#10;0"
></ion-textarea>
</div>
`,
config
);
const container = page.locator('#container');
await expect(container).toHaveScreenshot(screenshot(`textarea-rows-shapes`));
});

await expect(textarea).toHaveScreenshot(screenshot(`textarea-rows-3`));
});

test('should respect rows attribute with different values', async ({ page }) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we combine this with should respect rows attribute and set min-height with the following:

rows=1
rows=3
rows=5 (or some other larger number)

and then just capture the same screenshots in different sizes? So there would be 3 tests:

// test 1
"small"
rows=1
rows=3
rows=5 (or some other larger number)

// test 2
"medium"
rows=1
rows=3
rows=5 (or some other larger number)

// test 3
"large"
rows=1
rows=3
rows=5 (or some other larger number)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implemented.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

package: core @ionic/core package

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants