A Material Design framework for Flask, similar to flask-bootstrap. Utilizes Materialize CSS
JavaScript CSS HTML Python
Clone or download
HellerCommaA Merge pull request #7 from x1ah/patch-1
fixed bug when POST by quick_form(form)
Latest commit 3395b4d Jan 22, 2017


=============== Flask-Materialize

With the recent addition of Google's Material Design Lite, this project will soon be ported over to that framework and change names. http://www.getmdl.io/ However, this project will be maintained in this repo and on PyPi. More updates will follow.

Join the chat at https://gitter.im/HellerCommaA/flask-materialize

Scrutinizer Code Quality

Build Status

Flask-Material packages MaterializeCSS https://github.com/Dogfalo/materialize into an extension that mostly consists of a blueprint named 'material'. It can also create links to serve Materialize from a CDN and works with no boilerplate code in your application.


A quick demo applicdation can be seen at http://flask-template-materia.elasticbeanstalk.com/
This demo is a clone of https://github.com/HellerCommaA/flask-template-materialize


First, easily install the package with pip install flask-material

A sample helloworld app:
Yes, I know this is a long helloworld, but, you'll have a great base to start with if you follow along!

from flask import Flask, render_template  
from flask_material import Material  
from flask_wtf import Form, RecaptchaField
from flask_wtf.file import FileField
from wtforms import TextField, HiddenField, ValidationError, RadioField,\
    BooleanField, SubmitField, IntegerField, FormField, validators
from wtforms.validators import Required

app = Flask(__name__)  

# straight from the wtforms docs:
class TelephoneForm(Form):
    country_code = IntegerField('Country Code', [validators.required()])
    area_code = IntegerField('Area Code/Exchange', [validators.required()])
    number = TextField('Number')

class ExampleForm(Form):
    field1 = TextField('First Field', description='This is field one.')
    field2 = TextField('Second Field', description='This is field two.',
    hidden_field = HiddenField('You cannot see this', description='Nope')
    recaptcha = RecaptchaField('A sample recaptcha field')
    radio_field = RadioField('This is a radio field', choices=[
        ('head_radio', 'Head radio'),
        ('radio_76fm', "Radio '76 FM"),
        ('lips_106', 'Lips 106'),
        ('wctr', 'WCTR'),
    checkbox_field = BooleanField('This is a checkbox',
                                  description='Checkboxes can be tricky.')

    # subforms
    mobile_phone = FormField(TelephoneForm)

    # you can change the label as well
    office_phone = FormField(TelephoneForm, label='Your office phone')

    ff = FileField('Sample upload')

    submit_button = SubmitField('Submit Form')

    def validate_hidden_field(form, field):
        raise ValidationError('Always wrong')

def hello_world():
      form = ExampleForm()   
      return render_template('test.html', form = form)  

if __name__ == '__main__':  
    app.run(debug = True)  

templates/test.html with silly macros

{% extends "material/base.html" %}
{% import "material/utils.html" as util %}
{% import "material/wtf.html" as wtf %}

{% block title %}Hello, world!{% endblock %}

{% block content %}
{{ container() }}
        {{ row() }}
                {{ col(['s12', 'm6']) }}
                	{{ util.card('Hello world!', wtf.quick_form(form) )}}
                {{ enddiv() }}
                {{ col(['s12', 'm6'])}}
                	{{ util.card('Isn\'t Flask great?', '<p>I really do enjoy it!</p>', [['https://github.com/HellerCommaA', 'My Github']])}}
            	{{ enddiv() }}
        {{ enddiv() }}
{{ enddiv() }}
{% endblock %}

OR templates/test.html without silly macros

{% extends "material/base.html" %}
{% import "material/utils.html" as util %}
{% import "material/wtf.html" as wtf %}

{% block title %}Hello, world!{% endblock %}

{% block content %}
<div class="container">
        <div class="row">
                <div class="col s12 m6">
                	{{ util.card('Hello world!', wtf.quick_form(form) )}}
                <div class="col s12 m6">
                	{{ util.card('Isn\'t Flask great?', '<p>I really do enjoy it!</p>', [['https://github.com/HellerCommaA', 'My Github']])}}
{% endblock %}

This makes some new templates available, containing blank pages that include all Material resources, and have predefined blocks where you can put your content.

Available Blocks

{{block doc}}

Starts: Above <!DOCTYPE html>
Ends: Below </html>

{{block html_attribs}}  

Starts: Inside the <html> tag
Ends: Inside the <html> tag

{{block head}}

Starts: Just after the <head> tag
Ends: Just before the </head> tag

{{block title}}

Starts: Just inside the <title> tag
Ends: Before </title> tag

{{block metas}}

Starts: Inside the <head> block, after </title>. Automatically includes
<meta name="viewport" content="width=device-width, initial-scale=1.0"> Be sure to call super() if you want this meta tag
Ends: Within <head> block, just before {{block styles}}

{{block styles}}

Starts: Inside the head block, after the metas block closes. Includes a link to material.css be sure to call super()
Ends: Just before </head>

{{block body_attribs}}

Starts: Just after <body
Ends: Just before > in the top <body> tag.
<body{% block body_attribs %}{% endblock body_attribs %}>

{{block body}}

Starts: Immediately after <body>
Contains: {{block navbar}}
Contains: {{block content}}
Contains: {{block scripts}} which includes materialize.js and jquery.js, be sure to call super
Contains: {{block footer}}
Ends: Just above </body>

Available Macros

Be sure you are using {% import "material/utils.html" as util %} in your HTML document.

Simply do: {{ util.icon('ICON-NAME-WITHOUT-MDI', ['SIZE', 'OPTIONAL-CSS-CLASSES']) }}

Macro prototype: {{ util.form_button(content, class = [], type='submit', name='action', icon = False, iconclass=[] }}

Class already includes btn. Everything else must be added.  
<button class="btn {{ class|join(' ') }}" type="{{type}}" name="{{name}}">{{content}}
{% if icon %}<i class="{{ iconclass|join(' ') }} right"></i>{% endif %}</button>

Card prototype: {{ util.card('CARD-TITLE', 'CARD-CONTENT-CAN-USE-HTML-HERE', [['http://google.com/LINK.html', 'Link Title'], ['http://www.google.co.uk/link2.html', 'Link Title2']]) }}
Card does not include any row, or column sizes. You must wrap the card in your desired size.

**These may or may not be useful, feedback requested. **

{{ container() }} Generates <div class="container">

{{ row() }} Generates <div class="row">

{{ col( ['s12', 'm6'] ) }} Generates <div class="col s12 m6">

{{ enddiv() }} Generates </div>


  • Fix WTF forms integration (quick form)
  • Finish documentation


This is largely a fork from the excellent work at https://github.com/mbr/flask-bootstrap