Skip to content

Commit 06ace54

Browse files
feat(toolbar): add titlePlacement prop to control title position relative to content (#31034)
Issue number: internal --------- ## What is the current behavior? The `ionic` theme currently only supports aligning the toolbar title to the center. ## What is the new behavior? - Adds `titlePlacement` property to toolbar - This property currently only works for the `ionic` theme as it is the only theme that supports the new center implementation - Set to `"start"` to place the title to the left in LTR and to the right in RTL - Set to `"center"` to center the title within the toolbar - Set to `"end"` to place the title to the right in LTR and to the left in RTL - Adds an e2e test for `title-placement` which takes screenshots for the `ionic` theme only ## Does this introduce a breaking change? - [ ] Yes - [x] No --------- Co-authored-by: Brandy Smith <6577830+brandyscarney@users.noreply.github.com>
1 parent 8f1b005 commit 06ace54

File tree

30 files changed

+263
-10
lines changed

30 files changed

+263
-10
lines changed

core/api.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2754,6 +2754,7 @@ ion-toolbar,shadow
27542754
ion-toolbar,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secondary" | "success" | "tertiary" | "warning" | string & Record<never, never> | undefined,undefined,false,true
27552755
ion-toolbar,prop,mode,"ios" | "md",undefined,false,false
27562756
ion-toolbar,prop,theme,"ios" | "md" | "ionic",undefined,false,false
2757+
ion-toolbar,prop,titlePlacement,"center" | "end" | "start" | undefined,undefined,false,false
27572758
ion-toolbar,css-prop,--background,ionic
27582759
ion-toolbar,css-prop,--background,ios
27592760
ion-toolbar,css-prop,--background,md

core/src/components.d.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4463,6 +4463,10 @@ export namespace Components {
44634463
* The theme determines the visual appearance of the component.
44644464
*/
44654465
"theme"?: "ios" | "md" | "ionic";
4466+
/**
4467+
* Where to place the title relative to the other toolbar content. `"start"`: The title will appear to the left of the toolbar content in LTR and to the right in RTL. `"center"`: The title will appear in the center of the toolbar. `"end"`: The title will appear to the right of the toolbar content in LTR and to the left in RTL. Only applies in the `ionic` theme.
4468+
*/
4469+
"titlePlacement"?: 'start' | 'center' | 'end';
44664470
}
44674471
}
44684472
export interface IonAccordionGroupCustomEvent<T> extends CustomEvent<T> {
@@ -10590,6 +10594,10 @@ declare namespace LocalJSX {
1059010594
* The theme determines the visual appearance of the component.
1059110595
*/
1059210596
"theme"?: "ios" | "md" | "ionic";
10597+
/**
10598+
* Where to place the title relative to the other toolbar content. `"start"`: The title will appear to the left of the toolbar content in LTR and to the right in RTL. `"center"`: The title will appear in the center of the toolbar. `"end"`: The title will appear to the right of the toolbar content in LTR and to the left in RTL. Only applies in the `ionic` theme.
10599+
*/
10600+
"titlePlacement"?: 'start' | 'center' | 'end';
1059310601
}
1059410602

1059510603
interface IonAccordionAttributes {
@@ -11382,6 +11390,7 @@ declare namespace LocalJSX {
1138211390
}
1138311391
interface IonToolbarAttributes {
1138411392
"color": Color;
11393+
"titlePlacement": 'start' | 'center' | 'end';
1138511394
}
1138611395

1138711396
interface IntrinsicElements {
-531 Bytes
Loading
-431 Bytes
Loading
-578 Bytes
Loading
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
<!DOCTYPE html>
2+
<html lang="en" dir="ltr">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<title>Toolbar - Title Placement</title>
6+
<meta
7+
name="viewport"
8+
content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"
9+
/>
10+
<link href="../../../../../css/ionic.bundle.css" rel="stylesheet" />
11+
<link href="../../../../../scripts/testing/styles.css" rel="stylesheet" />
12+
<script src="../../../../../scripts/testing/scripts.js"></script>
13+
<script nomodule src="../../../../../dist/ionic/ionic.js"></script>
14+
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
15+
</head>
16+
17+
<body>
18+
<ion-app>
19+
<ion-header id="default-placement">
20+
<ion-toolbar>
21+
<ion-title>Default Placement</ion-title>
22+
</ion-toolbar>
23+
<ion-toolbar>
24+
<ion-buttons slot="start">
25+
<ion-button>
26+
<ion-icon slot="icon-only" name="menu"></ion-icon>
27+
</ion-button>
28+
</ion-buttons>
29+
<ion-title>Default Placement</ion-title>
30+
</ion-toolbar>
31+
<ion-toolbar>
32+
<ion-title>Default Placement</ion-title>
33+
<ion-buttons slot="primary">
34+
<ion-button>
35+
<ion-icon slot="icon-only" name="search"></ion-icon>
36+
</ion-button>
37+
</ion-buttons>
38+
</ion-toolbar>
39+
</ion-header>
40+
<ion-header>
41+
<ion-toolbar title-placement="start">
42+
<ion-title>Start Placement</ion-title>
43+
</ion-toolbar>
44+
<ion-toolbar title-placement="start">
45+
<ion-buttons slot="start">
46+
<ion-button>
47+
<ion-icon slot="icon-only" name="menu"></ion-icon>
48+
</ion-button>
49+
</ion-buttons>
50+
<ion-title>Start Placement</ion-title>
51+
</ion-toolbar>
52+
<ion-toolbar title-placement="start">
53+
<ion-title>Start Placement</ion-title>
54+
<ion-buttons slot="primary">
55+
<ion-button>
56+
<ion-icon slot="icon-only" name="search"></ion-icon>
57+
</ion-button>
58+
</ion-buttons>
59+
</ion-toolbar>
60+
</ion-header>
61+
<ion-header>
62+
<ion-toolbar title-placement="center">
63+
<ion-title>Center Placement</ion-title>
64+
</ion-toolbar>
65+
<ion-toolbar title-placement="center">
66+
<ion-buttons slot="start">
67+
<ion-button>
68+
<ion-icon slot="icon-only" name="menu"></ion-icon>
69+
</ion-button>
70+
</ion-buttons>
71+
<ion-title>Center Placement</ion-title>
72+
</ion-toolbar>
73+
<ion-toolbar title-placement="center">
74+
<ion-title>Center Placement</ion-title>
75+
<ion-buttons slot="primary">
76+
<ion-button>
77+
<ion-icon slot="icon-only" name="search"></ion-icon>
78+
</ion-button>
79+
</ion-buttons>
80+
</ion-toolbar>
81+
</ion-header>
82+
<ion-header>
83+
<ion-toolbar title-placement="end">
84+
<ion-title>End Placement</ion-title>
85+
</ion-toolbar>
86+
<ion-toolbar title-placement="end">
87+
<ion-buttons slot="start">
88+
<ion-button>
89+
<ion-icon slot="icon-only" name="menu"></ion-icon>
90+
</ion-button>
91+
</ion-buttons>
92+
<ion-title>End Placement</ion-title>
93+
</ion-toolbar>
94+
<ion-toolbar title-placement="end">
95+
<ion-title>End Placement</ion-title>
96+
<ion-buttons slot="primary">
97+
<ion-button>
98+
<ion-icon slot="icon-only" name="search"></ion-icon>
99+
</ion-button>
100+
</ion-buttons>
101+
</ion-toolbar>
102+
</ion-header>
103+
104+
<ion-footer>
105+
<ion-button onclick="toggleTitlePlacement('start')">Start</ion-button>
106+
<ion-button onclick="toggleTitlePlacement('center')">Center</ion-button>
107+
<ion-button onclick="toggleTitlePlacement('end')">End</ion-button>
108+
</ion-footer>
109+
</ion-app>
110+
111+
<script>
112+
const defaultPlacementToolbars = document.querySelectorAll('#default-placement ion-toolbar');
113+
114+
function toggleTitlePlacement(placement) {
115+
defaultPlacementToolbars.forEach((toolbar) => {
116+
toolbar.titlePlacement = placement;
117+
});
118+
}
119+
</script>
120+
121+
<style>
122+
ion-footer {
123+
display: flex;
124+
125+
justify-content: center;
126+
align-items: center;
127+
128+
gap: 10px;
129+
padding: 8px;
130+
}
131+
</style>
132+
</body>
133+
</html>
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { expect } from '@playwright/test';
2+
import { configs, test } from '@utils/test/playwright';
3+
4+
/**
5+
* Title placement is only supported by the `ionic` theme.
6+
*/
7+
configs({ modes: ['ionic-md'] }).forEach(({ title, screenshot, config }) => {
8+
test.describe(title('toolbar: title-placement'), () => {
9+
['start', 'center', 'end'].forEach((placement) => {
10+
test(`should not have visual regressions with ${placement} placement`, async ({ page }) => {
11+
const placementTitle = placement.charAt(0).toUpperCase() + placement.slice(1);
12+
13+
await page.setContent(
14+
`
15+
<ion-header>
16+
<ion-toolbar title-placement="${placement}">
17+
<ion-title>${placementTitle} Placement</ion-title>
18+
</ion-toolbar>
19+
<ion-toolbar title-placement="${placement}">
20+
<ion-buttons slot="start">
21+
<ion-button>
22+
<ion-icon slot="icon-only" name="menu"></ion-icon>
23+
</ion-button>
24+
</ion-buttons>
25+
<ion-title>${placementTitle} Placement</ion-title>
26+
</ion-toolbar>
27+
<ion-toolbar title-placement="${placement}">
28+
<ion-title>${placementTitle} Placement</ion-title>
29+
<ion-buttons slot="primary">
30+
<ion-button>
31+
<ion-icon slot="icon-only" name="search"></ion-icon>
32+
</ion-button>
33+
</ion-buttons>
34+
</ion-toolbar>
35+
</ion-header>
36+
`,
37+
config
38+
);
39+
40+
const header = page.locator('ion-header');
41+
await expect(header).toHaveScreenshot(screenshot(`toolbar-title-placement-${placement}`));
42+
});
43+
});
44+
});
45+
});
Loading
Loading
Loading

0 commit comments

Comments
 (0)