Generation, signature, verification, and some more crypto operations are performed with the standard browser Crypto APIs (https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypt...).
Storage of the private key is another thing. For a web app it is difficult to acces a hardware-based storage system. So typically it is stored in Localstorage or IndexdedDB, encrypted using a user-provided password. It is possible (but very involved and I have not seen web apps using it) to use WebAuthn for that.