I'm not sure if this is the "right" way or even a good thing to do, but...
library(tidyverse)
df_ncol = function(df_name) {
ncol(eval(sym(df_name)))
}
sym turns the string into a name and eval evaluates it. You could use base as.name instead of sym.
The function is not vectorized, but you can vectorize it with:
df_ncol = Vectorize(df_ncol)
Then...
df_ncol("df1")
#> df1
#> 1
dfs %>% mutate(cols = df_ncol(df))
#> # A tibble: 2 x 2
#> df cols
#> <chr> <int>
#> 1 df1 1
#> 2 df2 2