Imagine typing a paragraph, the cursor blinking as you search for the perfect source. You pull up a webpage, draft your sentence, and then hit a wall: you need an APA citation, fast. You don’t want to leave your writing window or disrupt your flow. What if you could summon a perfect APA citation with a single click, right inside your editor?
In this tutorial, you’ll learn how to extend Froala with a lightweight, reusable citation feature. Build a custom toolbar button that opens a popup, collect author/date/title/URL details, and insert a polished APA website citation exactly where you’re writing.
Along the way, you’ll quickly grasp what citations are, why APA matters, and how Froala’s flexibility makes this tool fit real writing workflows.
By the end, you’ll see that Froala isn’t just a text editor—it’s a powerful tool you can shape to fit specialized workflows, whether you’re supporting academic writing, content publishing, or collaborative editing. Get ready to add a professional-grade citation tool to Froala and give your users a smoother, smarter writing experience.
Takeaways
- You can extend Froala with a lightweight, reusable citation tool that inserts APA website citations directly at the cursor.
- The approach emphasizes a clean, lazy-loaded popup to minimize performance impact.
- You can adapt the UI and formatter to support additional citation styles and branding requirements.
Understanding Citations
A citation gives credit to the source of information you use in your work. It helps readers verify facts, find more information, and ensures you avoid plagiarism. Citations apply whether you quote someone directly or paraphrase their ideas.
By contrast, a quotation is when you copy the exact words from a source. Quotations must always be followed by a citation. In short: quotations are the borrowed words, citations are the credit.
Citations appear in academic papers, blogs, reports, and any content where proper credit matters.
What is APA Citation Style?
The American Psychological Association (APA) style is one of the most widely used citation formats, especially in the social sciences.
A typical APA website citation includes:
- Author (person or organization)
- Date (year, month, and day if available)
- Title of the webpage (italicized)
- Website name (if different from the author)
- URL
Examples:
- Individual author: Smith, J. (2023, May 10). How to write a research paper. Writing Guide. https://www.writingguide.org/research-paper
- Organization author: World Health Organization. (2022, March 14). COVID-19 advice for the public. https://www.who.int/emergencies/diseases/novel-coronavirus-2019/advice-for-public
This structure ensures consistency and clarity for readers.
Why Extend Froala Editor with a Citation Feature?
Froala is more than a text editor—it’s a tool that developers can adapt to almost any content workflow. Writers, students, and professionals often need to insert citations, yet most editors don’t include citation tools by default.
Adding a custom citation button saves time, reduces formatting errors, and improves user experience. It also demonstrates how easily Froala can be tailored for specialized tasks. For example, to work as knowledge publishing or academic writing tool.
Step-by-Step Guide For Adding A Citation Feature
We will create a custom plugin named “Citation“. This plugin will register a new toolbar button to open the citation popup. The popup collects the citation details. You’ll need form fields for author, date, title, website name, and URL.
On submit, format the input as an APA website citation and insert it at the current cursor position.
Creating the Custom Citation Plugin
Define the popup template and the show/hide popup methods.
// Define popup template. Object.assign(FroalaEditor.POPUP_TEMPLATES, { "citationPlugin.popup": "[_BUTTONS_][_CUSTOM_LAYER_][_CBUTTONS_]", }); // Define popup buttons. Object.assign(FroalaEditor.DEFAULTS, { citationPopupTopButtons: ["popupClose", "|"], citationPopupBottomButtons: ["citationSubmit", "|"], }); // The custom popup is defined inside a plugin (new or existing). FroalaEditor.PLUGINS.citationPlugin = function (editor) { // Create custom popup. function initPopup() { // Load popup template. var template = FroalaEditor.POPUP_TEMPLATES["citationPlugin.popup"]; if (typeof template == "function") template = template.apply(editor); // Popup buttons. var citation_popup_top_buttons = ""; // Create the list of buttons. if (editor.opts.citationPopupTopButtons.length > 1) { citation_popup_top_buttons += '<div class="fr-buttons">'; citation_popup_top_buttons += editor.button.buildList( editor.opts.citationPopupTopButtons, ); citation_popup_top_buttons += "</div>"; } var citation_popup_bottom_buttons = ""; // Create the list of buttons. if (editor.opts.citationPopupBottomButtons.length > 1) { citation_popup_bottom_buttons += '<div class="fr-buttons">'; citation_popup_bottom_buttons += editor.button.buildList( editor.opts.citationPopupBottomButtons, ); citation_popup_bottom_buttons += "</div>"; } var citationPopupTemplate = ` <div class="fr-citation-popup"> <div class="fr-citation-input"> <label>Author:</label><input type="text" id="citation-author"></div> <div class="fr-citation-input"> <label>Date:</label><input type="text" id="citation-date"></div> <div class="fr-citation-input"> <label>Title:</label><input type="text" id="citation-title"></div> <div class="fr-citation-input"> <label>Website:</label><input type="text" id="citation-website"></div> <div class="fr-citation-input"> <label>URL:</label><input type="text" id="citation-url"></div> </div>`; // Load popup template. var template = { buttons: citation_popup_top_buttons, custom_layer: citationPopupTemplate, cbuttons: citation_popup_bottom_buttons, }; // Create popup. var $popup = editor.popups.create("citationPlugin.popup", template); return $popup; } // Show the popup function showPopup() { // Get the popup object defined above. var $popup = editor.popups.get("citationPlugin.popup"); // If popup doesn't exist then create it. // To improve performance it is best to create the popup when it is first needed // and not when the editor is initialized. if (!$popup) $popup = initPopup(); // Set the editor toolbar as the popup's container. editor.popups.setContainer("citationPlugin.popup", editor.$tb); // If the editor is not displayed when a toolbar button is pressed, then set BODY as the popup's container. // editor.popups.setContainer('citationPlugin.popup', $('body')); // Trigger refresh for the popup. // editor.popups.refresh('citationPlugin.popup'); // This custom popup is opened by pressing a button from the editor's toolbar. // Get the button's object in order to place the popup relative to it. var $btn = editor.$tb.find('.fr-command[data-cmd="citation"]'); // Compute the popup's position. var left = $btn.offset().left + $btn.outerWidth() / 2; var top = $btn.offset().top + (editor.opts.toolbarBottom ? 10 : $btn.outerHeight() - 10); // Show the custom popup. // The button's outerHeight is required in case the popup needs to be displayed above it. editor.popups.show("citationPlugin.popup", left, top, $btn.outerHeight()); } // Hide the custom popup. function hidePopup() { editor.popups.hide("citationPlugin.popup"); } // Methods visible outside the plugin. return { showPopup: showPopup, hidePopup: hidePopup, }; };
This popup provides a simple input form for the citation.
Note: The code structure is designed to keep the popup creation lazy (only when needed) for performance.
Add a custom button to open the popup
Register a new command named “citation” and connect it to the plugin. The button lives on the Froala toolbar and triggers the popup when pressed. If the popup is already visible, it hides it.
// Add custom citation button FroalaEditor.DefineIcon("citation", { template: "svgMultiplePath", PATHS: `<g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <g id="network"></g> <g id="connection"></g> <g id="page"></g> <g id="support"></g> <g id="configuration"></g> <g id="cloud_storage"></g> <g id="password"></g> <g id="search_engine"></g> <g id="history"></g> <g id="SEO"></g> <g id="optimization"></g> <g id="backlink"></g> <g id="performance"></g> <g id="analytics"></g> <g id="security"></g> <g id="dark_web"></g> <g id="video_player"></g> <g id="upload_download"></g> <g id="incognito_tab"></g> <g id="bookmark"> <g> <path d="M88.1,55l7.9-19.6c0.1-0.3,0.1-0.7-0.1-0.9C95.6,34.2,95.3,34,95,34h-7V17c0-2.8-2.2-5-5-5H17c-2.8,0-5,2.2-5,5v17H5 c-0.3,0-0.6,0.2-0.8,0.4c-0.2,0.3-0.2,0.6-0.1,0.9L11.9,55L4.1,74.6c-0.1,0.3-0.1,0.7,0.1,0.9C4.4,75.8,4.7,76,5,76h7v7 c0,2.8,2.2,5,5,5h66c2.8,0,5-2.2,5-5v-7h7c0.3,0,0.6-0.2,0.8-0.4c0.2-0.3,0.2-0.6,0.1-0.9L88.1,55z M17,14h66c1.7,0,3,1.3,3,3v5 H14v-5C14,15.3,15.3,14,17,14z M14,24h72v10H14V24z M86,83c0,1.7-1.3,3-3,3H17c-1.7,0-3-1.3-3-3v-7h72V83z M6.5,74l7.5-18.6 c0.1-0.2,0.1-0.5,0-0.7L6.5,36h87l-7.5,18.6c-0.1,0.2-0.1,0.5,0,0.7L93.5,74H6.5z"></path> <circle cx="80" cy="18" r="2"></circle> <circle cx="74" cy="18" r="2"></circle> <circle cx="68" cy="18" r="2"></circle> <path d="M65.5,50H54.4L51,39.4c-0.1-0.4-0.5-0.7-1-0.7s-0.8,0.3-1,0.7L45.6,50H34.5c-0.4,0-0.8,0.3-1,0.7c-0.1,0.4,0,0.9,0.4,1.1 l9,6.5l-3.4,10.6c-0.1,0.4,0,0.9,0.4,1.1c0.4,0.3,0.8,0.3,1.2,0l9-6.5l9,6.5c0.2,0.1,0.4,0.2,0.6,0.2s0.4-0.1,0.6-0.2 c0.4-0.3,0.5-0.7,0.4-1.1l-3.4-10.6l9-6.5c0.4-0.3,0.5-0.7,0.4-1.1C66.3,50.3,65.9,50,65.5,50z M55.3,57.1 c-0.4,0.3-0.5,0.7-0.4,1.1l2.7,8.3l-7.1-5.1c-0.2-0.1-0.4-0.2-0.6-0.2s-0.4,0.1-0.6,0.2l-7.1,5.1l2.7-8.3c0.1-0.4,0-0.9-0.4-1.1 L37.6,52h8.8c0.4,0,0.8-0.3,1-0.7L50,43l2.7,8.3c0.1,0.4,0.5,0.7,1,0.7h8.8L55.3,57.1z"> </path> </g> </g> </g>`, VIEWBOX: "0 0 100 100", }); FroalaEditor.RegisterCommand("citation", { title: "Insert Citation", undo: false, focus: false, popup: true, // Buttons which are included in the editor toolbar should have the plugin property set. plugin: "citationPlugin", callback: function () { if (!this.popups.isVisible("citationPlugin.popup")) { this.citationPlugin.showPopup(); } else { if (this.$el.find(".fr-marker")) { this.events.disableBlur(); this.selection.restore(); } this.popups.hide("citationPlugin.popup"); } }, });
Here, we define a new icon and tell Froala what to do when the user clicks it.
Add a close button for the popup
Define a close icon (popupClose) and wire it to hide the popup.
This button allows users to close the popup without inserting a citation.
// Define custom popup close button icon and command. FroalaEditor.DefineIcon("popupClose", { SVG_KEY: "back" }); FroalaEditor.RegisterCommand("popupClose", { title: "Close", undo: false, focus: false, callback: function () { this.citationPlugin.hidePopup(); }, });
Handle form submission (APA formatting)
Add a new button (citationSubmit). When clicked, it triggers the following actions:
- Read the form fields.
- Build the APA website citation string.
- Insert the citation into the editor at the cursor position.
- Close the popup afterward.
// Define custom popup close button icon and command. FroalaEditor.DefineIcon("citationSubmit", { template: "svgMultiplePath", PATHS: `<g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"><path d="M905.92 237.76a32 32 0 0 0-52.48 36.48A416 416 0 1 1 96 512a418.56 418.56 0 0 1 297.28-398.72 32 32 0 1 0-18.24-61.44A480 480 0 1 0 992 512a477.12 477.12 0 0 0-86.08-274.24z" fill="#231815"></path><path d="M630.72 113.28A413.76 413.76 0 0 1 768 185.28a32 32 0 0 0 39.68-50.24 476.8 476.8 0 0 0-160-83.2 32 32 0 0 0-18.24 61.44zM489.28 86.72a36.8 36.8 0 0 0 10.56 6.72 30.08 30.08 0 0 0 24.32 0 37.12 37.12 0 0 0 10.56-6.72A32 32 0 0 0 544 64a33.6 33.6 0 0 0-9.28-22.72A32 32 0 0 0 505.6 32a20.8 20.8 0 0 0-5.76 1.92 23.68 23.68 0 0 0-5.76 2.88l-4.8 3.84a32 32 0 0 0-6.72 10.56A32 32 0 0 0 480 64a32 32 0 0 0 2.56 12.16 37.12 37.12 0 0 0 6.72 10.56zM230.08 467.84a36.48 36.48 0 0 0 0 51.84L413.12 704a36.48 36.48 0 0 0 51.84 0l328.96-330.56A36.48 36.48 0 0 0 742.08 320l-303.36 303.36-156.8-155.52a36.8 36.8 0 0 0-51.84 0z" fill="#231815"></path></g>`, VIEWBOX: "0 0 1024 1024", }); FroalaEditor.RegisterCommand("citationSubmit", { title: "Close", undo: false, focus: false, callback: function () { //Read values from inputs: citation-author, citation-date, citation-title, citation-website, citation-url var author = document.getElementById('citation-author').value; var date = document.getElementById('citation-date').value; var title = document.getElementById('citation-title').value; var website = document.getElementById('citation-website').value; var url = document.getElementById('citation-url').value; //Build APA string var citation = `<p>${author}. (${date}). <cite>${title}</cite>. ${website}. ${url}</p>`; // Insert into Froala editor this.html.insert(citation); // close the popup this.citationPlugin.hidePopup(); }, });
Optional: style the inserted citation
You can also wrap citations in a consistent container for styling —for example, wrapping it in a <p class="citation">
.citation { font-size: 0.9em; color: #555; }
Style the form (popup)
Add basic layout/styling for the form inside the popup.
Example CSS:
.fr-citation-popup { padding: 10px; } .fr-citation-popup label{ width: 75px; display: inline-block; } .fr-citation-popup input{ padding: 5px; margin-bottom: 5px; border-radius: 7px !important; border: 1px solid #333 !important; }
Initialize the editor with the new button
Include the citation button in the Froala toolbar.
const editor = new FroalaEditor("#editor", { toolbarButtons: [ ["bold", "italic", "underline", "fontSize", "lineHeight"], ["alignLeft", "alignCenter", "alignRight"], ["citation", "textColor", "backgroundColor"], ["insertLink", "html"], ], });
After you follow our step-by-step guide, you’ll end up with:
- A single, reusable plugin named “Citation”
- A toolbar button labeled Citation
- A popup form to collect author, date, title, website name, and URL
- APA-formatted website citations inserted at the cursor position
- Optional styling hooks to ensure consistent appearance
Enhancements and Tips
- Validation: Require fields like Author and Title to prevent incomplete citations.
- Support Multiple Citation Formats: Add options for MLA or Chicago to support more audiences.
- Links: Make URLs clickable so readers can follow sources directly.
- Citation Block: Insert citations in a styled container for better readability.
Conclusion
We started with the basics of citations and APA style, then walked through creating a custom button, building a popup, handling input, and inserting formatted citations. This small feature demonstrates how powerful and customizable Froala really is.
With just a few lines of JavaScript, you transformed Froala into an academic-friendly writing tool. Now, you can extend this feature further—support more citation styles, build citation libraries, or connect to external reference managers.
Froala gives you the building blocks; your creativity defines what’s possible.
Try adding this citation button to your own Froala editor setup. Explore Froala’s documentation to see what else you can customize, and consider expanding the feature to support your users’ unique workflows. With Froala, the editor grows with your needs.