Vários editores de texto rico na mesma página

Crie um formulário com dois editores, IDs exclusivos, HTML separado e redefinição com confirmação.
Mantenha uma instância por campo
Um formulário de produto pode precisar de resumo e descrição. Crie um editor por contêiner e mantenha as referências em um mapa. Carregue CSS, núcleo e plugins uma única vez. Não reutilize IDs nem sobrescreva as instâncias em uma variável. São documentos independentes, não raízes de um documento compartilhado.
Execute o exemplo completo
Sirva os arquivos pela aplicação. O exemplo mostra o HTML atual como JSON com textContent, sem innerHTML. Não salva nem envia requisições. Restaurar só o resumo mantém os detalhes; restaurar ambos exige confirmação. Alterações limpam a prévia antiga.
<link rel="stylesheet" href="/richtexteditor/rte_theme_default.css">
<script src="/richtexteditor/rte.js"></script>
<script src="/richtexteditor/plugins/all_plugins.js"></script>
<style>body{font:16px/1.6 system-ui;max-width:960px;margin:24px auto;padding:0 16px}section{min-width:0;margin-block:20px}.editor-scroll{max-width:100%;overflow-x:auto}button{min-height:44px;padding:8px 16px;margin:8px 8px 0 0}pre{white-space:pre-wrap;overflow-wrap:anywhere}</style>
<h1>Two editors, two independent fields</h1>
<form id="product-form">
<section aria-labelledby="summary-heading">
<h2 id="summary-heading">Summary</h2>
<div class="editor-scroll"><div id="summary-editor"></div></div>
<button type="button" id="restore-summary">Restore summary</button>
</section>
<section aria-labelledby="details-heading">
<h2 id="details-heading">Details</h2>
<div class="editor-scroll"><div id="details-editor"></div></div>
</section>
<button type="submit">Inspect both fields</button>
<button type="reset">Restore both fields</button>
<p id="status" role="status" aria-live="polite"></p>
<pre id="payload"></pre>
</form>
<script>
// Load the assets once. Give every host its own unique ID and instance.
const initial = {
summary: "<p>A short <strong>product summary</strong>.</p>",
details: "<h2>Details</h2><p>A separate document with its own formatting.</p>"
};
const editors = {
summary: new RichTextEditor("#summary-editor", { toolbar: "full", height: "240px" }),
details: new RichTextEditor("#details-editor", { toolbar: "full", height: "320px" })
};
const form = document.getElementById("product-form");
const status = document.getElementById("status");
const output = document.getElementById("payload");
function resetFields() {
for (const key of Object.keys(editors)) editors[key].setHTMLCode(initial[key]);
}
resetFields();
function invalidatePreview() {
output.textContent = "";
status.textContent = "Draft changed. Inspect again to see current values.";
}
for (const instance of Object.values(editors)) instance.attachEvent("change", invalidatePreview);
document.getElementById("restore-summary").addEventListener("click", () => {
if (!confirm("Restore only the summary?")) return;
editors.summary.setHTMLCode(initial.summary);
invalidatePreview();
});
form.addEventListener("reset", event => {
if (!confirm("Restore both documents?")) { event.preventDefault(); return; }
resetFields();
output.textContent = "";
status.textContent = "Both initial documents restored. Nothing saved.";
});
function collect() {
return Object.fromEntries(Object.entries(editors).map(([key, instance]) => [key, instance.getHTMLCode()]));
}
form.addEventListener("submit", event => {
event.preventDefault();
// Read both live instances now; never use whichever editor last had focus.
output.textContent = JSON.stringify(collect(), null, 2);
status.textContent = "Current fields shown below. No request sent.";
});
window.multipleDemo = { editors, initial, collect };
</script>
Salve e valide cada campo
Use chaves estáveis como summary e details. Leia ambas as instâncias no envio, independentemente do último foco. O servidor deve autorizar o registro, validar e sanitizar cada HTML. Em erros, preserve os dois rascunhos e indique o campo afetado. Defina se o par deve ser salvo atomicamente.
Coordene salvamento automático e redefinição
Use uma chave por documento ou um registro versionado para o par. Compartilhar uma chave local pode sobrescrever outro rascunho. Redefinir no navegador não cancela gravações no servidor, exclui arquivos nem cria backup. Defina primeiro a fila e a política de versões.
Lista de aceitação
Edite os dois campos e alterne o foco antes de inspecionar. Restaure um e confirme que o outro HTML é idêntico. Cancele a redefinição completa. Teste JSON longo, emoji, teclado e telas de 320px. Muitas barras completas consomem memória e espaço: meça o formulário antes de criar dezenas de instâncias.