I would use cut insted of if_else or case_when-formulas:
library(dplyr)
df <- tibble::tribble(
~person, ~age,
"A", 5L,
"B", 27L,
"C", 66L,
"D", 9L,
"E", 4L,
"F", 8L,
"G", 1L,
"H", 58L,
"I", 44L,
"J", 30L,
"K", 19L,
"L", 18L,
"M", 87L,
"N", 23L,
"O", 5L,
"P", 30L,
"Q", 40L,
"R", 60L,
"S", 80L,
"T", 79L,
"U", 0L
)
dfage_grp <- df %>%
mutate(age_group = cut(age, breaks = c(0, 18, 40, 80, 100), include.lowest = T, labels = c("0-18","19-40", "41-80", "81-100")))