Here is a simple example:
library(cards)
library(gtsummary)
adsl <- cards::ADSL %>%
dplyr::mutate(
SAFFL = dplyr::if_else(SAFFL == "Y", "Y", NA_character_),
ITTFL = dplyr::if_else(ITTFL == "Y", "Y", NA_character_),
EFFFL = dplyr::if_else(EFFFL == "Y", "Y", NA_character_),
COMP8FL = dplyr::if_else(COMP8FL == "Y", "Y", NA_character_)
)
group_vars <- c("SAFFL", "ITTFL", "EFFFL", "COMP8FL")
tbl_list <- lapply(group_vars, function(var) {
gtsummary::tbl_hierarchical(
data = adsl,
denominator = adsl,
id = USUBJID,
by = .data[[var]],
variables = c(SITEGR1, SITEID),
)
})
tbl <- gtsummary::tbl_merge(tbls = tbl_list) |>
gtsummary::modify_spanning_header(dplyr::everything() ~ NA_character_) |>
gtsummary::modify_header(stat_1_1 = "**SAFFL** \n(N = {n})",
stat_1_2 = "**ITTFL** \n(N = {n})",
stat_1_3 = "**EFFFL** \n(N = {n})",
stat_1_4 = "**COMP8FL** \n(N = {n})") |>
remove_footnote_header(columns = everything())
tbl
However, I got all percentages equal to 100%:

Where did it go wrong?
Assuming you are after the percentage of each count relative to their group instead of 100%, you need to include the groups in denominator of tbl_hierarchical().
tbl_list <- lapply(group_vars, function(var) {
gtsummary::tbl_hierarchical(
data = adsl,
denominator = adsl %>%
select(USUBJID, all_of(var)),
id = USUBJID,
by = .data[[var]],
variables = c(SITEGR1, SITEID)
)
})