Many apps have shared UI elements that appear on every page — navigation header, footer, sidebar. Instead of duplicating these locators in every page class, create separate component classes and compose them into page objects.
package com.practice.pages.components;
import com.practice.pages.BasePage;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
public class HeaderComponent extends BasePage {
private By logo = By.cssSelector(".header-logo");
private By userMenu = By.id("user-menu");
private By logoutLink = By.id("logout-link");
private By notificationBell = By.id("notification-bell");
public HeaderComponent(WebDriver driver) {
super(driver);
}
public void clickLogo() {
click(logo);
}
public void navigateTo(String linkText) {
click(By.linkText(linkText));
}
public void clickLogout() {
click(userMenu);
click(logoutLink);
}
}package com.practice.pages.components;
import com.practice.pages.BasePage;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
public class SidebarComponent extends BasePage {
private By menuItems = By.cssSelector(".sidebar-menu-item");
private By activeItem = By.cssSelector(".sidebar-menu-item.active");
public SidebarComponent(WebDriver driver) {
super(driver);
}
public void clickMenuItem(String text) {
click(By.xpath(
"//div[contains(@class,'sidebar-menu-item')]" +
"[contains(text(),'" + text + "')]"));
}
public String getActiveMenuItem() {
return getText(activeItem);
}
public int getMenuItemCount() {
return findElements(menuItems).size();
}
}Now compose these components into your page objects using composition (has-a relationship):
public class DashboardPage extends BasePage {
// Components — shared across pages
public HeaderComponent header;
public SidebarComponent sidebar;
// Page-specific locators
private By welcomeMessage = By.id("welcome-message");
private By accountBalance = By.id("account-balance");
public DashboardPage(WebDriver driver) {
super(driver);
this.header = new HeaderComponent(driver);
this.sidebar = new SidebarComponent(driver);
}
}
// In tests:
// dashboard.header.clickLogout();
// dashboard.sidebar.clickMenuItem("Transfers");Use composition (has-a) for page components, not inheritance (is-a). A DashboardPage HAS a header and sidebar. It is NOT a type of header. Composition keeps your class hierarchy clean and flexible.
Key Point: Extract shared UI elements into component classes. Compose them into page objects using has-a relationships.