Prerequisite:
This tutorial is part of the Flask CKEditor Project Series.
Preliminary
Before I begin, it is recommended to activate the virtual environment before installing the relevant dependencies.
python -m venv venv
venv\Scripts\activate
pip install flask flask-wtf flask-ckeditor
The next step is to set up an app structure; they are app.py, form.py, and the templates folder. Within the templates folder is contact.html. The app structure is described in the following diagram:
Let us set up the app.py by importing the necessary module and configuration.
Step 2: Set up the form widgets
from flask import Flask, render_template
app = Flask(__name__)
app.config['SECRET_KEY'] = 'mysecretkey'
@app.route('/')
def index():
return render_template('contact.html')
if __name__ == '__main__':
app.run(host='127.0.0.1', port=8000, debug=True)
Meanwhile, the following is the minimum setup for contact.html. I have added a header and subheader at the top of the page.<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Contact Form</title>
</head>
<body>
<h1>Keep In Touch 🤙</h1>
<h5>We welcome your feedback and suggestions. We'll reply to you in 3 business days.</h5>
</body>
</html>
Let us define what the widgets are in the form.py. For the name and email fields, I will use StringField and always validate them. For the subscription and button, I use BooleanField and SubmitField.
from flask_wtf import FlaskForm
from wtforms import StringField, BooleanField, SubmitField
from wtforms.validators import DataRequired
class ContactForm(FlaskForm):
name = StringField('Name:', validators=[DataRequired()])
email = StringField('Email:', validators=[DataRequired()])
subscribe = BooleanField("Subscribe to our newsletter?")
submit = SubmitField("Submit ☺️")
Then, we need to import the ContactForm from form.py into app.py and perform all the necessary setup in the index function.
from flask import Flask, render_template
from form import ContactForm
app = Flask(__name__)
app.config['SECRET_KEY'] = 'mysecretkey'
@app.route('/')
def index():
# Create an instance of the ContactForm
form = ContactForm()
# The form object is sent to the template so it can be displayed and used
return render_template('contact.html', form=form)
if __name__ == '__main__':
app.run(host='127.0.0.1', port=8000, debug=True)
Now, we can set up a form to contain the widget in the contact.html.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Contact Form</title>
</head>
<body>
<h1>Keep In Touch 🤙</h1>
<h5>We welcome your feedback and suggestions. We'll reply to you in 3 business days.</h5>
<form method="post" action="">
{{ form.hidden_tag() }}
<p>
{{ form.name.label }}
{{ form.name(size=32) }}<br>
</p>
<p>
{{ form.email.label }}
{{ form.email(size=32) }}<br>
</p>
<p>
{{ form.subscribe() }} {{ form.subscribe.label }}
</p>
<p class="submit-container">
{{ form.submit(class="btn-submit") }}
</p>
</form>
</body>
</html>
Finally, let us check out how it looks.
Step 3: Initialise and configure the Flask-CKEditorFirst, let's import the module and initialise it in the app.py
The web page will display as the below view.
from flask import Flask, render_template
from form import ContactForm
from flask_ckeditor import CKEditor
app = Flask(__name__)
# Initialize CKEditor and attach it to the Flask application
ckeditor = CKEditor(app)
app.config['SECRET_KEY'] = 'mysecretkey'
# Specify the CKEditor package type to load
app.config['CKEDITOR_PKG_TYPE'] = 'full-all'
@app.route('/')
def index():
# Create an instance of the ContactForm
form = ContactForm()
# The form object is sent to the template so it can be displayed and used
return render_template('contact.html', form=form)
if __name__ == '__main__':
app.run(host='127.0.0.1', port=8000, debug=True)
Then, I have added the CKEditor widget in between the email and subscription widgets on the contact.html.<p>
{{ ckeditor.load() }}
{{ ckeditor.config() }}
<label>Comment:</label>
{{ ckeditor.create() }}
</p>Step 4: Style the contact.html
To gain a better outlook, as shown in the cover diagram above, I have styled the contact.html file with CSS as follows:
<style>
body {
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
padding: 20px;
font-family: 'Roboto', sans-serif;
justify-content: center;
align-items: center;
margin: 50px 100px 50px 100px;
border-radius: 5px;
}
h1 {
color: #2c4d3d;
text-align: center;
}
h5 {
font-size: 18px;
color: #333333;
text-align: center;
font-style: italic;
}
label {
font-weight: bold;
margin-top: 10px;
padding-right: 50px;
}
input[type="text"],
input[type="email"] {
border: 4px solid #2c4d3d;
border-radius: 5px;
padding: 5px;
}
.btn-submit {
justify-content: center;
width: 200px;
background-color: #2c4d3d;
color: white;
border: none;
padding: 10px 20px;
border-radius: 5px;
font-size: 16px;
cursor: pointer;
}
.btn-submit:hover {
background-color: #21b348;
color: black;
}
p.submit-container {
text-align: center;
}
.cke {
border: 4px solid #2c4d3d !important;
border-radius: 5px;
}
</style>To run the Flask app, in the terminal, type the command below:
python app.py
The following information will be shown, and just click the link provided: http://127.0.0.1:8000
Final wrap-up:Currently, this implementation supports only CKEditor 4.22.1 (Full). Support for newer versions is not yet available, but future updates are expected as the ecosystem evolves. Stay tuned for improvements and enhancements ahead.
Published: Feb 2026
Last Updated: Feb 2026
About the Author
Kelvin Loh is a Python developer focused on Flask, desktop applications, and business automation solutions. He shares practical tutorials and real-world coding projects to help developers and small businesses build useful applications.





Comments
Post a Comment