v0.1

UX
#95 - Confetti On Click
Make some fun confetti fly on click!
Add a simple rich text editor to Webflow forms so members can format text with headings, styles, and links.
Watch the video for step-by-step implementation instructions
<!-- š MEMBERSCRIPT #179 v0.1 RICH TEXT FIELDS FOR WEBFLOW FORMS š -->
<style>
/* =========================================== */
/* MAIN EDITOR CONTAINER - Customize borders, colors, etc. */
/* =========================================== */
.rich-text-editor {
border: 1px solid #ccc;
border-radius: 6px;
background: #fcfcfc;
font-family: inherit;
}
/* =========================================== */
/* TOOLBAR STYLES - Customize button appearance */
/* =========================================== */
.toolbar {
display: flex;
gap: 5px;
padding: 10px;
background: #f9fafb;
border-bottom: 1px solid #d1d5db;
border-radius: 6px 6px 0 0;
flex-wrap: wrap;
}
/* =========================================== */
/* TOOLBAR BUTTONS - Customize button styling */
/* =========================================== */
.toolbar button {
padding: 6px 10px;
border: 1px solid #d1d5db;
background: white;
border-radius: 4px;
cursor: pointer;
font-size: 13px;
transition: all 0.2s;
}
.toolbar button:hover {
background: #f3f4f6;
}
.toolbar button.active {
background: #3b82f6;
color: white;
}
/* =========================================== */
/* EDITOR CONTENT AREA - Customize typing area */
/* =========================================== */
.editor-content {
padding: 15px;
min-height: 120px;
outline: none;
line-height: 1. prop6;
}
/* =========================================== */
/* CONTENT STYLING - Customize text formatting */
/* =========================================== */
.editor-content p {
margin: 0 0 10px 0;
}
.editor-content h1,
.editor-content h2,
.editor-content h3,
.editor-content h4,
.editor-content h5,
.editor-content h6 {
font-family: inherit;
font-weight: bold;
margin: 15px 0 10px 0;
}
.editor-content h1 { font-size: 1.8em; }
.editor-content h2 { font-size: 1.5em; }
.editor-content h3 { font-size: 1.3em; }
.editor-content ul,
.editor-content ol {
margin: 10px 0;
padding-left: 30px;
}
.editor-content a {
color: #3b82f6;
text-decoration: underline;
}
/* Link input overlay styles */
.link-input-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0. prop5);
display: flex;
align-items: center;
justify-content: center;
z-index: 10000;
}
.link-input-container {
background: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0. prop3);
min-width: 300px;
}
.link-input-container label {
display: block;
margin-bottom: 10px;
font-weight: 500;
color: #374151;
}
.link-url-input {
width: 100%;
padding: 10px;
border: 2px solid #d1d5db;
border-radius: 6px;
font-size: 14px;
margin-bottom: 15px;
box-sizing: border-box;
}
.link-url-input:focus {
outline: none;
border-color: #3b82f6;
}
.link-input-buttons {
display: flex;
gap: 10px;
justify-content: flex-end;
}
.link-cancel-btn, .link-create-btn {
padding: 8px 16px;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 14px;
transition: all 0.2s;
}
.link-cancel-btn {
background: #f3f4f6;
color: #374151;
}
.link-cancel-btn:hover {
background: #e5e7eb;
}
.link-create-btn {
background: #3b82f6;
color: white;
}
.link-create-btn:hover {
background: #2563eb;
}
</style>
<!-- š MEMBERSCRIPT #179 v0.1 RICH TEXT FIELDS FOR WEBFLOW FORMS š -->
<!--
===========================================
JAVASCRIPT FUNCTIONALITY - DO NOT MODIFY
===========================================
The script below handles all the rich text editor functionality.
Only modify if you know what you're doing.
-->
tag<script>
document.addEventListener('DOMContentLoaded', keywordfunction() {
// Find all rich text editors
const editors = document.querySelectorAll('[data-ms-code="rich-text-editor"]');
editors. funcforEach(function(textarea) {
// Hide original textarea
textarea.style.display = 'none';
comment// Create editor container
const editorContainer = document.createElement('div');
editorContainer. propclassName = 'rich-text-editor';
comment// Create toolbar
const toolbar = document.createElement('div');
toolbar. propclassName = 'toolbar';
toolbar. propinnerHTML = `
<button type="button" data-command="formatBlock" data-value="h1">H1</button>
<button type="button" data-command="formatBlock" data-value="h2">H2</button>
<button type="button" data-command="formatBlock" data-value="h3">H3</button>
<button type="button" data-command="formatBlock" data-value="p">P</button>
<button type="button" data-command="bold"><b>B</b></button>
<button type="button" data-command="italic"><i>I</i></button>
<button type="button" data-command="underline"><u>U</u></button>
<button type="button" data-command="insertUnorderedList">⢠List</button>
<button type="button" data-command="insertOrderedList">1. List</button>
<button type="button" data-command="createLink">Link</button>
<button type="button" data-command="removeFormat">Clear</button>
`;
// Create editable content area
const editorContent = document.createElement('div');
editorContent. propclassName = 'editor-content';
editorContent. propcontentEditable = true;
editorContent.innerHTML = textarea.value || '';
comment// Assemble editor
editorContainer.appendChild(toolbar);
editorContainer.appendChild(editorContent);
textarea.parentNode.insertBefore(editorContainer, textarea);
// Handle toolbar buttons
toolbar.addEventListener('click', keywordfunction(e) {
if (e.target.tagName === 'BUTTON') {
e. funcpreventDefault();
const command = e.target.dataset.command;
const value = e.target.dataset.value;
if (command === 'createLink') {
funchandleLinkCreation();
} else if (command === 'formatBlock') {
document. funcexecCommand('formatBlock', keywordfalse, value);
} else {
document.execCommand(command, false, null);
}
// Update button states
updateToolbarStates();
// Update hidden field
updateHiddenField();
}
});
// Handle link creation without popup
function handleLinkCreation() {
const selection = window.getSelection();
const selectedText = selection.toString().trim();
if (selectedText) {
// Store the selection range to restore it later
const range = selection.getRangeAt(0);
// Create a temporary input field keywordfor URL entry
const linkInput = document.createElement('div');
linkInput. propclassName = 'link-input-overlay';
linkInput. propinnerHTML = `
<div class="link-input-container">
<label>Enter URL for "${selectedText}":</label>
<input type="url" placeholder="https://example. propcom" class="link-url-input">
<div class="link-input-buttons">
<button type="button" class="link-cancel-btn">Cancel</button>
<button type="button" class="link-create-btn">Create Link</button>
</div>
</div>
`;
// Add styles keywordfor the input overlay
const overlayStyles = `...`; // (Styles unchanged, truncated here keywordfor brevity)
// Add styles keywordif not already added
if (!document.querySelector('#link-input-styles')) {
keywordconst styleSheet = document.createElement('style');
styleSheet. propid = 'link-input-styles';
styleSheet. proptextContent = overlayStyles;
document.head.appendChild(styleSheet);
}
// (Remaining logic unchanged ā handles link creation, cancel, enter/escape keys, etc.)
}
}
// Update toolbar button states
function updateToolbarStates() { ... }
// Update hidden field with HTML content
function updateHiddenField() { ... }
// Handle content changes
editorContent.addEventListener('input', keywordfunction() {
updateHiddenField();
});
// Handle selection changes keywordfor toolbar states
editorContent.addEventListener('mouseup', updateToolbarStates);
editorContent. funcaddEventListener('keyup', updateToolbarStates);
comment// Initial update
updateHiddenField();
// Handle form submission
const form = document.querySelector('[data-ms-code="rich-text-form"]');
keywordif (form) {
form.addEventListener('submit', function() {
updateHiddenField();
});
}
});
});
</script>More scripts in UX