Blueprint by Tiny
Return to Tiny.cloud
Return to Tiny.cloudTry TinyMCE for Free
Search by

How to get started with image uploads using Bootstrap

Anshuman Bhardwaj

August 17th, 2022

Written by

Anshuman Bhardwaj

Category

How-to Use TinyMCE

Over the past decade, mobile devices have become the main means of entering your website. Now, more than 68% of website visitors use a mobile device, which means it’s crucial for every business to create mobile-first websites for their customers.

More than a decade ago, a large web-based business understood this new (at the time) business imperative. In late August 2010, Twitter engineers Mark Otto, and Jacob Thornton released a CSS framework called Bootstrap. It’s since expanded to become one of the most popular development frameworks.

What is Bootstrap?

Bootstrap provides CSS and JavaScript utilities to more efficiently build production-ready responsive websites. It’s a valuable component for mobile-first web design.

Many organizations include it in their productions, with 26% of all websites using Bootstrap. It’s one of several pre-built components (like WYSIWYG editors) that help power websites, but harmony between those components can’t be ignored..

TinyMCE integrates well with several popular frameworks, including Bootstrap, and brings with it functionality that’s useful for mobile devices such as image upload and image editing.

That’s what this tutorial explains – how to build a blog submission web page using Bootstrap –making a responsive page for different screen sizes, and also integrating the TinyMCE WYSIWYG editor to support rich text formatting. Finally, this guide shows how to implement TinyMCE’s image upload feature with a Node.js server.

Note: The code content for this how-to guide is available in this GitHub repository.

Why should you use Bootstrap?

Apart from its mobile-first approach, what else makes Bootstrap stand out?

  • It provides a library of CSS components powered by JavaScript, which can be used to build beautiful applications from scratch.
  • It supports all major browsers and performs CSS normalization to avoid issues related to browser settings, therefore creating a consistent user experience.
  • Bootstrap is open source and anyone can contribute to the code on GitHub – open source projects can respond to change more quickly as an open source project.

What makes images so important to mobile devices?

The truth is, it’s not just mobile devices. Looking at the web broadly, the value that images add to content affects all digital experiences. Images are a vital part of content marketing, especially on blogs and landing pages. They increase visitor engagement and make the content come to life. 

Because visual content and images have become so crucial, businesses need reliable components that help them build beautiful blogs fast. That’s where TinyMCE’s image handling functions come in. But to see these functions in action, the first step is creating a project demo.

Step 1. Initializing an npm project

To start, create a new project with npm init —y. Create a ./public folder inside your project, then create an index.html file inside that folder with the content below:

  <head>
    <meta charset="UTF-8" /> <meta
      name="viewport" content="width=device-width, user-scalable=no,
      initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
    /> <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Create a new blog</title>
  </head> <body> </body>
</html>

Step 2: Adding bootstrap to the project

Add Bootstrap CSS to the <head> element of the HTML file to enable utility classes and components:

<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css"
  integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3"
  crossorigin="anonymous"
/> 

Add Bootstrap JavaScript to the <body> element of the HTML file to enable interactive components like dialogs:

<script
  src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"
  integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p"
  crossorigin="anonymous"
></script>;

Step 3: Creating a blog submission page

With Bootstrap in place, create a simple layout for the blog submission page in index.html:

  <h1 class="display-2">Your new blog</h1> <div class="form row
  mt-4">
    <div class="form-group col-sm">
      <label for="title">Title</label> <input type="text"
      class="form-control" id="title" />
    </div>

  </div>

  <div class="form col mt-4">
    <div class="form-group">
      <label for="articleBody">Write a ~1500 word article</label>
      <textarea id="articleBody" rows="20" cols="150"></textarea>
    </div> <div class="form-group mt-4">
      <label for="keywords">Keywords</label> <input type="text"
      class="form-control" id="keywords" /> <small id="keywordsHelp"
      class="form-text text-muted" >Comma separated list of
      keywords.</small >
    </div>
  </div>

  <div class="form row mt-4">
    <div class="form-group col-sm">
      <button
	name="submitbtn" class="btn btn-primary"
      >
	Publish
      </button>
    </div>
  </div>

</div>

TinyMCE minimal editor working in Bootstrap

The form looks neat, but the article editor is minimal. It also doesn’t support rich text editing or media. The other missing element is image upload. By using TinyMCE to add these elements, it helps create a better user experience, and introduces image functionality.

Step 4: Configuring TinyMCE

To integrate with TinyMCE, first sign up for an API key. You can then add your API key into the TinyMCE JavaScript CDN link. Include the link at the top of the html page inside the head tags:

<script
  src="https://cdn.tiny.cloud/1/no-api-key/tinymce/6/tinymce.min.js"
  referrerpolicy="origin"
></script>;

Signing up for an API key removes any warnings on domain registration. It also gives you 14 days FREE access to TinyMCE premium plugins.

Initialize the TinyMCE editor inside a <script> tag with the Bootstrap skin and focus effect. You can get more details on how to enable Bootstrap text editor here. The tinymce.init script here also includes plugins for handling images.

Note: The script includes the TinyMCE Accessibility Checker plugin as including images with correct alt text is essential for websites.

// initialize TinyMCE rich text editor
<script>
            tinymce.init({
                selector: "textarea#articleBody",
                skin: 'bootstrap',
                icons: 'bootstrap',
                plugins: 'image link media editimage a11ychecker',
                toolbar: ' a11ychecker | undo redo | styles | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image',
                a11y_advanced_options: true,
                setup: (editor) => {
                    editor.on("init", () => {
                        editor.getContainer().style.transition = "border-color 0.15s ease - in - out, box - shadow 0.15 s ease - in - out ";
                    });
                    editor.on("focus", () => {
                        (editor.getContainer().style.boxShadow = "0 0 0 .2rem rgba(0, 123, 255, .25)"),
                        (editor.getContainer().style.borderColor = "#80bdff");
                    });
                    editor.on("blur", () => {
                        (editor.getContainer().style.boxShadow = ""),
                        (editor.getContainer().style.borderColor = "");
                    });
                }
            });
        </script>

To avoid bugs while using a Bootstrap dialog, disable event propagation from the editor to interactive components like Bootstrap dialogs:

  // Prevent Bootstrap dialog from blocking focusin
  document.addEventListener("focusin", (e) => {
    if (
	e.target.closest(
    ".tox-tinymce, .tox-tinymce-aux, .moxman-window,
    .tam-assetmanager-root"
	) !== null
    ) {
      e.stopImmediatePropagation();
    }
  });

Enhanced TinyMCE image upload with Bootstrap

Step 5: Extracting data from the editor

In the same <script> tag, create a function to extract the content from the editor on the onclick event of the Publish button:

async function handleForm() {
  const editor = tinymce.activeEditor; const data = editor.getContent({
  format: "html" }); console.log({ data }) // store data into your
  database or content management system (CMS)
}

Add the onclick handler function to the Publish button created in the previous step number 3:

<button name="submitbtn" onclick="handleForm()" class="btn btn-primary">
  Publish
</button>;

TinyMCE with Bootstrap

The article submission page looks good, and it supports images as well. Still, you’ll notice two issues: 

  1. The images in the final content have Blob URLs while using the format: 'raw', which won’t be accessible outside of this system
  2. The images use base64 while using format: 'html', which will increase image sizes

To handle image uploads correctly, you first need to set up a REST API to store images in a remote location. This example uses Express, but you can use whatever framework you’re most comfortable with.

Step 6: Setting up the Express server

Run npm i express@4.18.1 to install Express. Create a server.js file at the root of the project to serve the HTML files:

const express = require("express");
const server = express();
const PORT = 8080;

server.use(express.static("public"));

server.listen(PORT, () => {
  console.log(`server is running at port: ${PORT}`);
});

Run node server.js to start the server. You’ll be able to access the page at http://localhost:8080.

Step 7: Uploading images using a REST API endpoint

Create a ./images folder inside the project. This tutorial uses Multer to handle the multipart/form-data and save uploaded images to the ./images folder. Run npm i multer@1.4.5-lts.1 to install Multer. Then, run npm i nanoid@3.3.4 to install Nano ID in order to generate unique file names for the uploaded images.

Update the server.js code to enable image uploads:

const express = require("express"); const server =
express(); const PORT = 8080; const multer = require("multer");
const { nanoid } = require("nanoid");

// serve HTML file from /public folder at "/" path
server.use(express.static("public"));

// serve the uploaded images from ./images folder at "./images"
path server.use("/images", express.static("images"));

// configure storage options for multer const fileStorageEngine =
multer.diskStorage({
  destination: (req, file, cb) => {
    cb(null, "./images"); // relative path to storage location
  }, filename: (req, file, cb) => {
    // get the file extension from mimetype const fileExtension =
    file.mimetype.split("/")[1]; // create a unique file name using
    10 random characters joined with time in milliseconds const
    uniqueFileName = `${nanoid(10)}-${Date.now()}.${fileExtension}`;
    cb(null, uniqueFileName);
  },
});

// initialize multer with the storage engine configuration const
upload = multer({ storage: fileStorageEngine });

// handle image upload using multer and return the `imageUrl` as
response server.post("/upload-image", upload.single("image"),
(request, response) => {
  response.send({
    imageUrl: `${request.headers.origin}/${request.file.path}`,
  });
});

// start the server at http://localhost:{PORT} server.listen(PORT,
() => {
  console.log(`server is running at port: ${PORT}`);
});

Step 8: Updating the frontend code to handle image upload

TinyMCE expects an images_upload_handler function to handle image uploads and return the location of the uploaded file. TinyMCE then replaces the image src in the editor content with the received URL.

In your index.html file , add a handleImage() function in your tinymce.init <script> tag to upload an image to the server:

  // this function will upload the images to the server // and
  return a Promise with file URL function handleImage(blobInfo) {
    const formData = new FormData() formData.set('image',
    blobInfo.blob())

    // upload the image to server and return `imageUrl` return
    fetch("/upload-image", {
      method: "post", body: formData,
    })
      .then((response) => response.json()) .then((res) => res.imageUrl);
  }

Update the TinyMCE initialization code to specify the images_upload_handler function:

>  // initialize the TinyMCE rich text editor tinymce.init({
  selector: "textarea#articleBody", skin: 'bootstrap', //The TinyMCE
  Bootstrap skin images_upload_handler: handleImage, // // ....other
  configurations
});

Update handleForm() to call editor.uploadImages() and ensure all images are uploaded:

async function handleForm() {
    const editor = tinymce.activeEditor; // make sure all images
    are uploaded on the server await editor.uploadImages(); const
    data = editor.getContent({ format: "html" }); // store data
    into your database or content management system (CMS)
}

TinyMCE updated to handle image upload

You can see that the image src is the server location and can be accessed directly. See it in action:

Bootstrap image upload and TinyMCE

TinyMCE effectively integrates into a Bootstrap web page, and handles both the crucial image upload and serving functions needed across websites. The Express server is just one method to handle images with the TinyMCE API. Other methods involve angular or jQuery. We’ll cover these methods in future articles.

To ensure reliability and faster access time, you can extend this example further by integrating with a Cloud storage provider like Tiny Drive. It’s another service available to support your application development.

BootstrapImagesTinyMCEProduct Development
byAnshuman Bhardwaj

Anshuman is a creative software engineer with more than four years of experience in software development, ranging from being an engineering manager to developing a full stack application which they published and released independently.

Related Articles

  • How-to Use TinyMCE

    How to migrate from Slate.js to TinyMCE

    by Ben Long in How-to Use TinyMCE
Subscribe for the latest insights served straight to your inbox every month.

Deploy TinyMCE in just 6 lines of code

Built to scale. Developed in open source. Designed to innovate.

Begin with your FREE API Key
Tiny Editor
Tiny logo
Privacy Policy - Terms of Use© 2022 Tiny Technologies Inc.TinyMCE® and Tiny® are registered trademarks of Tiny Technologies, Inc.

Products

  • TinyMCE
  • Tiny Drive
  • Customer Stories
  • Pricing