Most implementations[1] implement it in userland, but this is by no means a requirement. There is no implementation for the Linux kernel presently, but both msquic and F5's QUIC implementation can run in their respective kernels.
QUIC is indeed built on top of UDP datagrams, much in the same way TCP is built (typically) on top of IP datagrams.
Could QUIC also have been built on top of IP datagrams instead of UDP datagrams? Or does our crufty Internet mean only UDP and TCP are viable Internet protocols?
It is as you say. In theory you could build this as a new IP protocol next to TCP but in practice that would be blocked by default and can't be deployed.
QUIC is indeed built on top of UDP datagrams, much in the same way TCP is built (typically) on top of IP datagrams.
[1] https://github.com/quicwg/base-drafts/wiki/Implementations