Skip to content

Commit 0674b4a

Browse files
authored
fix(input): label position and overflow is correct (#26248)
1 parent 9a9568c commit 0674b4a

18 files changed

+60
-28
lines changed

core/src/components/input/input.md.outline.scss

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -60,17 +60,17 @@
6060
border-bottom: none;
6161
}
6262

63-
:host(.input-fill-outline.input-label-placement-stacked) label,
64-
:host(.input-fill-outline.input-label-placement-floating) label {
63+
:host(.input-fill-outline.input-label-placement-stacked) .label-text-wrapper,
64+
:host(.input-fill-outline.input-label-placement-floating) .label-text-wrapper {
6565
@include transform-origin(center, top);
6666
}
6767

6868
/**
6969
* The label should appear on top of an outline
7070
* container that overlaps it so it is always clickable.
7171
*/
72-
:host(.input-fill-outline) label,
73-
:host(.input-fill-outline) label {
72+
:host(.input-fill-outline) .label-text-wrapper,
73+
:host(.input-fill-outline) .label-text-wrapper {
7474
position: relative;
7575

7676
z-index: 1;
@@ -79,10 +79,10 @@
7979
/**
8080
* This makes the label sit above the input.
8181
*/
82-
:host(.has-focus.input-fill-outline.input-label-placement-floating) label,
83-
:host(.has-value.input-fill-outline.input-label-placement-floating) label,
84-
:host(.input-fill-outline.input-label-placement-stacked) label,
85-
:host(.input-fill-outline.input-label-placement-stacked) label {
82+
:host(.has-focus.input-fill-outline.input-label-placement-floating) .label-text-wrapper,
83+
:host(.has-value.input-fill-outline.input-label-placement-floating) .label-text-wrapper,
84+
:host(.input-fill-outline.input-label-placement-stacked) .label-text-wrapper,
85+
:host(.input-fill-outline.input-label-placement-stacked) .label-text-wrapper {
8686
@include transform(translateY(-32%), scale(.75));
8787
@include margin(0);
8888
}

core/src/components/input/input.md.scss

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,12 @@
7777
* When the input is focused the label should
7878
* take on the highlight color.
7979
*/
80-
:host(.has-focus) label {
80+
:host(.has-focus) .label-text-wrapper {
8181
color: var(--highlight-color);
8282
}
8383

84-
:host(.ion-touched.ion-valid) label,
85-
:host(.ion-touched.ion-invalid) label {
84+
:host(.ion-touched.ion-valid) .label-text-wrapper,
85+
:host(.ion-touched.ion-invalid) .label-text-wrapper {
8686
color: var(--highlight-color);
8787
}
8888

core/src/components/input/input.scss

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,7 @@
392392
// Input Label
393393
// ----------------------------------------------------------------
394394

395-
.input-wrapper label {
395+
.label-text-wrapper {
396396
/**
397397
* The margin between the label and
398398
* the input should be on the end
@@ -410,6 +410,34 @@
410410
align-items: center;
411411

412412
transition: color 150ms cubic-bezier(.4, 0, .2, 1), transform 150ms cubic-bezier(.4, 0, .2, 1);
413+
414+
/**
415+
* This ensures that double tapping this text
416+
* clicks the <label> and focuses the input
417+
* when a screen reader is enabled.
418+
*/
419+
pointer-events: none;
420+
}
421+
422+
/**
423+
* We need to use two elements instead of
424+
* one. The .label-text-wrapper is responsible
425+
* for centering the label text vertically regardless
426+
* of the input height using flexbox.
427+
*
428+
* The .label-text element is responsible for controlling
429+
* overflow when label-placement="fixed".
430+
* We want the ellipses to show up when the
431+
* fixed label overflows, but text-overflow: ellipsis only
432+
* works on block-level elements. A flex item is
433+
* considered blockified (https://www.w3.org/TR/css-display-3/#blockify).
434+
*/
435+
.label-text {
436+
text-overflow: ellipsis;
437+
438+
white-space: nowrap;
439+
440+
overflow: hidden;
413441
}
414442

415443
.input-wrapper input {
@@ -448,7 +476,7 @@
448476
* the input should be on the start
449477
* when the label sits at the end.
450478
*/
451-
:host(.input-label-placement-end) label {
479+
:host(.input-label-placement-end) .label-text-wrapper {
452480
@include margin(0, 0, 0, 8px);
453481
}
454482

@@ -459,9 +487,7 @@
459487
* Label is on the left of the input in LTR and
460488
* on the right in RTL. Label also has a fixed width.
461489
*/
462-
:host(.input-label-placement-fixed) label {
463-
@include margin(0, 0, 0, 0);
464-
490+
:host(.input-label-placement-fixed) .label-text {
465491
flex: 0 0 100px;
466492

467493
width: 100px;
@@ -490,8 +516,8 @@
490516
* up and to the left in LTR or
491517
* up and to the right in RTL.
492518
*/
493-
:host(.input-label-placement-stacked) label,
494-
:host(.input-label-placement-floating) label {
519+
:host(.input-label-placement-stacked) .label-text-wrapper,
520+
:host(.input-label-placement-floating) .label-text-wrapper {
495521
@include transform-origin(start, top);
496522
}
497523

@@ -508,7 +534,7 @@
508534
* This makes the label sit over the input
509535
* when the input is blurred and has no value.
510536
*/
511-
:host(.input-label-placement-floating) label {
537+
:host(.input-label-placement-floating) .label-text-wrapper {
512538
@include transform(translateY(100%), scale(1));
513539
}
514540

@@ -529,8 +555,8 @@
529555
/**
530556
* This makes the label sit above the input.
531557
*/
532-
:host(.input-label-placement-stacked) label,
533-
:host(.has-focus.input-label-placement-floating) label,
534-
:host(.has-value.input-label-placement-floating) label {
558+
:host(.input-label-placement-stacked) .label-text-wrapper,
559+
:host(.has-focus.input-label-placement-floating) .label-text-wrapper,
560+
:host(.has-value.input-label-placement-floating) .label-text-wrapper {
535561
@include transform(translateY(50%), scale(.75));
536562
}

core/src/components/input/input.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -560,7 +560,11 @@ export class Input implements ComponentInterface {
560560
return;
561561
}
562562

563-
return <label htmlFor={this.inputId}>{this.label}</label>;
563+
return (
564+
<div class="label-text-wrapper">
565+
<div class="label-text">{this.label}</div>
566+
</div>
567+
);
564568
}
565569

566570
/**
@@ -619,7 +623,7 @@ export class Input implements ComponentInterface {
619623
'in-full-item': hostContext('ion-item:not(.item-lines-inset)', this.el),
620624
})}
621625
>
622-
<div class="input-wrapper">
626+
<label class="input-wrapper">
623627
{this.renderLabelContainer()}
624628
<div class="native-wrapper">
625629
<input
@@ -674,7 +678,7 @@ export class Input implements ComponentInterface {
674678
)}
675679
</div>
676680
{shouldRenderHighlight && <div class="input-highlight"></div>}
677-
</div>
681+
</label>
678682
{this.renderBottomContent()}
679683
</Host>
680684
);

core/src/components/input/test/input.e2e.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ test.describe('input: rendering', () => {
1010
test('should not render the label element if no label was passed', async ({ page }) => {
1111
await page.setContent(`<ion-input aria-label="my hidden label"></ion-label>`);
1212

13-
const label = page.locator('ion-input label');
13+
const label = page.locator('ion-input .label-text-wrapper');
1414
await expect(label).toBeHidden();
1515
});
1616
});

core/src/components/input/test/label-placement/input.e2e.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,11 @@ test.describe('input: label placement end', () => {
2424
});
2525

2626
test.describe('input: label placement fixed', () => {
27-
test('label should appear on the starting side of the input and have a fixed width', async ({ page }) => {
27+
test('label should appear on the starting side of the input, have a fixed width, and show ellipses', async ({
28+
page,
29+
}) => {
2830
await page.setContent(`
29-
<ion-input label="Email" value="[email protected]" label-placement="fixed"></ion-input>
31+
<ion-input label="Email Email Email Email Email Email" value="[email protected]" label-placement="fixed"></ion-input>
3032
`);
3133

3234
const input = page.locator('ion-input');
719 Bytes
Loading
327 Bytes
Loading
346 Bytes
Loading
655 Bytes
Loading

0 commit comments

Comments
 (0)