Last updated: August 25, 2026.
A BBCode editor is a text area with controls that wrap the current selection in tags such as [b] and [url]. Store the BBCode source and convert it to a strict HTML allowlist on the server before displaying it.
Editor markup
<div class="bbcode-toolbar" aria-label="Formatting controls">
<button type="button" data-open="[b]" data-close="[/b]">Bold</button>
<button type="button" data-open="[i]" data-close="[/i]">Italic</button>
<button type="button" data-open="[url]" data-close="[/url]">Link</button>
</div>
<label for="message">Message</label>
<textarea id="message" name="message" rows="10"></textarea>Wrap the selected text
const editor = document.querySelector('#message');
document.querySelector('.bbcode-toolbar').addEventListener('click', event => {
const button = event.target.closest('button[data-open]');
if (!button) return;
const start = editor.selectionStart;
const end = editor.selectionEnd;
const selected = editor.value.slice(start, end);
const replacement = button.dataset.open + selected + button.dataset.close;
editor.setRangeText(replacement, start, end, 'select');
editor.focus();
});Render only allowed tags
<?php
function renderBbcode(string $source): string
{
$html = htmlspecialchars($source, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
$html = preg_replace('/\[b\](.*?)\[\/b\]/is', '<strong>$1</strong>', $html);
$html = preg_replace('/\[i\](.*?)\[\/i\]/is', '<em>$1</em>', $html);
return nl2br($html, false);
}Links, images, nesting, and malformed tags require a real parser rather than a growing set of regular expressions. Validate URL schemes and attributes explicitly, and never decode stored BBCode directly into unrestricted HTML.