feat(list-header): add inner part (#30930)

Issue number: N/A

---------

## What is the current behavior?
The inner structural element of list-header is not exposed as a shadow part, preventing users from being able to customize its styles directly.

## What is the new behavior?
- Exposes `inner` shadow part
- Adds e2e test coverage for customizing the shadow part

## Does this introduce a breaking change?
- [ ] Yes
- [x] No

---------

Co-authored-by: Brandy Smith <6577830+brandyscarney@users.noreply.github.com>
This commit is contained in:
Brandy Smith
2026-02-27 13:40:42 -05:00
committed by GitHub
parent f8f7ffda31
commit ef73476e08
3 changed files with 38 additions and 1 deletions

View File

@@ -1033,6 +1033,7 @@ ion-list-header,css-prop,--color,ios
ion-list-header,css-prop,--color,md
ion-list-header,css-prop,--inner-border-width,ios
ion-list-header,css-prop,--inner-border-width,md
ion-list-header,part,inner
ion-loading,scoped
ion-loading,prop,animated,boolean,true,false,false

View File

@@ -7,6 +7,8 @@ import type { Color } from '../../interface';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*
* @part inner - The inner wrapper element that arranges the list header content.
*/
@Component({
tag: 'ion-list-header',
@@ -40,7 +42,7 @@ export class ListHeader implements ComponentInterface {
[`list-header-lines-${lines}`]: lines !== undefined,
})}
>
<div class="list-header-inner">
<div class="list-header-inner" part="inner">
<slot></slot>
</div>
</Host>

View File

@@ -0,0 +1,34 @@
import { expect } from '@playwright/test';
import { configs, test } from '@utils/test/playwright';
/**
* This behavior does not vary across modes/directions
*/
configs({ directions: ['ltr'], modes: ['md'] }).forEach(({ title, config }) => {
test.describe(title('list-header: custom'), () => {
test.describe('CSS shadow parts', () => {
test('should be able to customize inner part', async ({ page }) => {
await page.setContent(
`
<style>
ion-list-header::part(inner) {
background-color: red;
}
</style>
<ion-list-header>Header</ion-list-header>
`,
config
);
const header = page.locator('ion-list-header');
const backgroundColor = await header.evaluate((el) => {
const shadowRoot = el.shadowRoot;
const inner = shadowRoot?.querySelector('.list-header-inner');
return inner ? window.getComputedStyle(inner).backgroundColor : '';
});
expect(backgroundColor).toBe('rgb(255, 0, 0)');
});
});
});
});