Hallo Samuel,
wer sich anbietet, erntet Kommentare 😉. Meine eigenen Beispiele mutieren auch immer einige Zeit lang vor sich hin, bis sie mir und anderen gefallen.
Nachdem ich deine Begründung für type="button" gelesen habe, fällt mir noch was auf.
Ein Form ohne Submit ist - meine ich - nicht so sinnvoll. Man kann aber, statt gar keinen Submit-Button zu haben, sich auf das submit-Event des Forms registrieren und im Submit-Handler mit event.preventDefault() den echten Submit unterbinden.
Ich würde das JS für das Beispiel dann so strukturieren:
document.addEventListener("DOMContentLoaded", function() {
	const formElement = document.forms.urlForm;
        
  
  formElement.addEventListener("submit", (submitEvent) => {
    
    submitEvent.preventDefault();
    
    generateURL();     
  });
  function generateURL() {
  ...
  }
});
Den DOMContentLoaded-Rahmen lässt man im Wiki-Artikel weg.
Diese Variante verwendet im HTML dann nur noch
<button>Download-URL generieren</button>
Die anonyme Funktion, die den Submit-Handler bildet, kümmert sich um das Stoppen des Submit. Das ist "single responsibility" - eine Funktion hat die Ablaufsteuerung, die andere Funktion bestückt den Link.
In generateURL kannst Du formElement nutzen und auch dessen Komfortfunktionen verwenden, also z.B. formElement.input_text ansprechen statt mit getElementById("input_text") zu hantieren. Das Link-Element kriegst Du so nicht erreicht, a Elemente sind keine Formelemente und tauchen darum in der elements-Collection eines Forms nicht auf.
Das ist jetzt nur eine Anregung, kein Auftrag. Mein Fiddle sieht so aus: https://jsfiddle.net/Rolf_b/6qh4yrwe/. Die textarea hat bei mir box-sizing:border-box, weil eine textarea per Default padding und border hat und deswegen width:100% ohne das box-sizing zu breit ist. Und Gunnars Flexbox-Idee für den p Container hab ich aufgegriffen.
Rolf
-- 
sumpsi - posui - obstruxi