Last updated on August 26, 2025
Tired of your ggplot2 plots looking a little… off-balance? The default left-aligned title works, but for a polished, professional-looking chart, a centered title often makes all the difference.
In this step-by-step tutorial, we’ll show you the quick and easy way to perfectly center your plot titles and subtitles. You’ll not only learn the main function but also understand how to customize alignment further for complete control over your plot’s appearance.
Quick Solution (TL;DR)
To center the plot title and subtitle in ggplot2, add a theme() layer to your plot and set the hjust (horizontal justification) argument to 0.5 inside element_text().
library(ggplot2)
theme_set(theme_bw(16))
# center title and subtitle with theme() and element_text()
mtcars |>
ggplot(aes(x = wt, y = mpg)) +
geom_point() +
labs(title = "My Centered Title",
subtitle = "My Centered Subtitle") +
theme(
plot.title = element_text(hjust = 0.5),
plot.subtitle = element_text(hjust = 0.5)
)
ggsave("Centered_title_and_subtitle_ggplot2.png")

Understanding the hjust Argument
The key to aligning text in ggplot2 is the horizontal justification argument, hjust. It controls the horizontal position of the text relative to its anchor point.
You can think of it as a scale from left to right:
-
hjust = 0: Left-justifies the text (this is the default for titles). -
hjust = 0.5: Center-justifies the text. -
hjust = 1: Right-justifies the text.
By setting plot.title = element_text(hjust = 0.5), you are telling ggplot2: “Take the title text element and position it so its horizontal center is aligned with the plot’s center.”
Step-by-Step Example: From Default to Centered
Now that we understand the theory, let’s walk through a complete example using the palmerpenguins dataset. First, we’ll load our libraries and create a plot with the default left-aligned title.
1. The Default Plot
Without any theme adjustments, the title appears on the left.
library(tidyverse)
library(palmerpenguins)
theme_set(theme_bw(16))
penguins |>
drop_na() |>
ggplot(aes(x = body_mass_g, fill = sex)) +
geom_density(alpha = 0.5) +
labs(title = "Body Mass Distribution",
subtitle = "Default Left-Aligned Title and SubTitle")

2. The Centered Plot
Now, let’s add our theme() layer to center both the title and the subtitle.
penguins |>
drop_na() |>
ggplot(aes(x = body_mass_g, fill = sex)) +
geom_density(alpha = 0.5) +
labs(title = "Body Mass Distribution",
subtitle = "Centered Title and Subtitle") +
# Center the title and subtitle
theme(plot.title = element_text(hjust = 0.5),
plot.subtitle = element_text(hjust = 0.5))
ggsave("centered_plot_title_subtitle_ggplot2.png")

Pro-Tip: Set Centered Titles as the Default
If you want all your plots in a script or report to have centered titles, you don’t need to add a theme() layer every time. Instead, you can set it globally at the beginning of your R script using theme_update().
# Run this code once at the top of your script theme_update(plot.title = element_text(hjust = 0.5)) # Now, any new plot you create will automatically have a centered title penguins |> drop_na() |> ggplot(aes(x = flipper_length_mm)) + geom_histogram() + labs(title = "This Title is Centered by Default")

Useful Extras: Captions, Long Titles, Facets, Export
Center or Right-Align the Caption
Captions sit at the bottom; you can align them too. Use plot.caption with hjust.
library(patchwork)
p <- penguins |>
drop_na() |>
ggplot(aes(x = body_mass_g,
y = bill_length_mm,
color=sex)) +
geom_point(alpha = 0.6) +
labs(title = "Centered Title",
caption = "Source: palmerpenguins")
# Center caption
p1 <- p + theme(plot.title = element_text(hjust = 0.5),
plot.caption = element_text(hjust = 0.5))
# Or right-align
p2 <- p + theme(plot.title = element_text(hjust = 0.5),
plot.caption = element_text(hjust = 1))
p1/p2
ggsave("ggplot2_align_caption.png", height=12, width=8)

Handle Long / Multi-Line Titles
Long titles wrap naturally. Improve readability with margins and line spacing.
library(stringr)
long_title <- str_wrap(
"Body Mass & Bill Length in Palmer Penguins: Centered Titles Improve Readability for Presentations and Publications",
width = 50
)
penguins |>
drop_na() |>
ggplot(aes(body_mass_g,
bill_length_mm)) +
geom_point(alpha = 0.6) +
labs(title = long_title,
subtitle = "Centered subtitle with extra spacing") +
theme(
plot.title = element_text(
hjust = 0.5,
lineheight = 1.1, # increases spacing between wrapped lines
margin = margin(b = 6) # adds bottom space below title
),
plot.subtitle = element_text(
hjust = 0.5,
margin = margin(b = 8) # creates breathing room above plot
)
)

In the example above
- lineheight = 1.1 → Adds gentle vertical space between wrapped lines of the title, so the text doesn’t look squashed.
- margin(b = 6) → Adds bottom padding below the title, separating it from the subtitle.
- margin(b = 8) for subtitle → Pushes the subtitle down a bit, so the block of text feels balanced above the plot.
Together, these adjustments make multi-line centered titles look visually balanced, improving overall readability.
Facets & Title Positioning
In faceted plots, the main plot title still aligns with the overall plot area. If it looks off, increase figure width, adjust margins, or consider
plot.title.position (e.g., theme(plot.title.position = "plot")) to control how the title/subtitle relate to panels vs. the full plot.
Export Cleanly (No Clipping)
Prevent cropped text with tight bounding boxes and adequate size.
ggsave("centered_title.png", width = 8, height = 5, units = "in", dpi = 300)
# Vector for print
ggsave("centered_title.pdf", width = 8, height = 5, units = "in")
ggplot2 title positioning: FAQs (Advanced & Edge Cases)
-
Will a top legend or large guide shift the title’s apparent center?
Yes—tall legends at the top can change visual balance even if the title is numerically centered. Keep the legend on the side, reduce legend rows, or add a small bottom margin to the title/subtitle so the header block reads as a single unit. -
How do I center titles when combining plots with patchwork or cowplot?
Center each subplot’s title withhjust = 0.5, then add a global title using patchwork’splot_annotation(title = ...)or cowplot’sggdraw() + draw_label(..., hjust = 0.5). Ensure the outer annotation is centered independently of panel widths. -
Can I use rich text (bold, color, line breaks) and still keep the title centered?
Yes, withggtext::element_markdown()intheme(plot.title = ...). Usehjust = 0.5and include Markdown/HTML (e.g.,<span style="color:#444">...</span>). Manage line breaks with<br>orstringr::str_wrap()for predictable wrapping. -
My theme settings keep overriding local title alignment—why?
Theme precedence matters:theme_set()→theme_update()→ plot-level+ theme(). The last applied theme takes priority. If a custom theme reassignsplot.title, add your+ theme(...)after the plot is built. -
How do I center the plot tag (e.g., “A”, “B”) like the title?
Uselabs(tag = "A")and style withtheme(plot.tag = element_text(hjust = 0.5)). Control vertical spacing viaplot.tag.positionandplot.marginfor alignment with the main title block. -
Can a logo or annotation in the header throw off perceived centering?
Yes. Place logos usingannotation_custom(),cowplot::ggdraw(), or patchwork areas, and balance them with equal padding/margins on the opposite side, or move the logo to a caption/footer bar. -
How can I systematically insert line breaks for long titles without guessing a width?
Usestringr::str_wrap(title, width = n)wherenis derived from container width or a heuristic (e.g., 45–60 for slides, 60–75 for print). For strict control, insert\nat semantic breakpoints and keeplineheightaround1.05–1.15. -
Can I shift only the first line of a multi-line title?
ggplot2 aligns the entire title block. To offset the first line only, split the title into two parts (first line intitle, rest insubtitle), or switch toggtext::element_markdown()and control alignment per line with HTML spans. -
Fonts look different after export—title seems off. What’s going on?
Font fallback or missing glyphs can change text width. Register and embed fonts (showtext/systemfonts), export to PDF/SVG for vector text, and verify the target font supports your language and weight. -
Does
plot.title.positionaffect centering in all themes?
It controls how titles/subtitles anchor to the plot vs panel area. Some custom themes alter layout enough that you may still need small manual tweaks (margins, legend placement, or container width) for perfect visual centering.
Explore the Complete ggplot2 Guide
35+ tutorials with code: scatterplots, boxplots, themes, annotations, facets, and more—tested and beginner-friendly.
Visit the ggplot2 Hub → No fluff—just code and visuals.


