Conceptually, using the @html directive is equivalent to doing el.innerHTML = myHtmlString.
Said otherwise, in the context of your HTML string, you're completely out of Svelte's realm (and completely in native browser's realm).
on:click is special Svelte syntax, the browser won't process that. So if you want events in you HTML string, you need to go back to raw HTML/JS. That is, use onclick instead.
Of course, the semantics of onclick are completely different from that of on:click. To onclick, you can only pass a string, that will be eval'd when the event happens (whereas with on:click, you pass a function reference, that will be called when the event happens).
To make this very clear, let's recall Svelte's syntax:
<button on:click={doSomething}>Click me</button>
In contrast, in raw HTML, this would look like:
{@html '<button onclick="doSomething()">Click click!</button>'}
See the important difference: with onclick, you need to call the doSomething() function, or nothing will happen on click.
Now, extra fun: this doSomething function needs to be available in scope... That is, you have to attach it to window:
<script context="module">
// note: using context=module to avoid adding this function to window
// multiple times
window.doSomething = () => { ... }
</script>
{@html '<button onclick="doSomething()">Click click!</button>'}
This is ugly... You could do something like this instead, to avoid polluting the global scope:
<script>
import { onMount } from 'svelte'
const doSomething = () => { ... }
onMount(() => {
const btn = document.querySelector('#grab-me')
btn.addEventListener('click', doSomething)
})
</script>
{@html '<button id="grab-me">Click click!</button>'}
Now we're polluting DOM ids... We could further avoid that by wrapping with an element that Svelte controls, to which we could grab a reference with bind:this={el}...
To sum it up, dynamic elements in @html strings are best avoided because you lose all the benefits of Svelte inside them. @html is best fitted for rendering static HTML content.
Why do you want to put your button in a string, instead of letting Svelte manage it?
If you really need going done this road, you might also be interested in this dirty trick, that I absolutely don't recommend to use (I would never use it in my own code)... But this might give you further perspective on what you're trying to achieve.