# Introduction

[**Flutter-view**](https://flutter-view.io) is an open source tool that makes writing reactive [Flutter](http://flutter.io) layouts a breeze. It lets you use [Pug](http://pugjs.org) and [Sass](http://sass-lang.com) to generate the Flutter Dart code that renders the views in your app.

You use it by running the `flutter-view` command in your terminal to let it monitor your project. When it detects changes in a Pug or Sass file, it automatically generates or updates a matching Dart file.

Flutter-view 2.0.0 and up fully support writing null-safe code in Dart 2.13 and up.

## Why views in Flutter

In standard Flutter Dart code, the "state" of your application is mixed in with the presentation. This can make it hard to structure and scale your code.

Flutter-view is about creating **views**, which are functions that return a widget tree for presenting something. These functions act a bit like components. Flutter-view uses **Pug** to make layouts more terse and **Sass** to let you style faster and more easily.

The state part comes into play when you make your view **reactive**. You can pass models (or streams) into your views. When these models change, the views automatically adapt.

## Creating a view

A single flutter-view in pug generates a Dart function that usually returns a widget tree.

{% tabs %}
{% tab title="Pug" %}
{% code title="hello.pug" %}

```c
hello(flutter-view)
    .greeting Hello world!
```

{% endcode %}
{% endtab %}

{% tab title="HTML" %}
{% code title="hello.html" %}

```markup
<hello flutter-view>
    <div class="greeting">
        Hello world!
    </div>
</hello>
```

{% endcode %}
{% endtab %}

{% tab title="Generated Dart" %}
{% code title="hello.dart" %}

```dart
Container Hello() {
    return Container(
        child: Text("Hello world!")
    );
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

*Click the tabs to see the Pug code, the HTML representation of the Pug, and the Dart code that flutter-view generates for you.*

This generated function can be used like any other Dart code, and will return the code that gives the greeting.

## Adding Styling

You can add Sass to style your view. These styles get mixed with your pug to generate styled Dart code. Flutter-view supports [CSS style properties](/reference/css-properties) that convert into code. For our example, you can easily add a text [**color**](/reference/css-properties#color-color), [**background color**](/reference/css-properties#box-shadow-2), some [**font properties**](/reference/css-properties#box-shadow-8), and add [**padding**](/reference/css-properties#padding):

{% tabs %}
{% tab title="Pug" %}
{% code title="hello.pug" %}

```c
hello(flutter-view)
    .greeting Hello world!
```

{% endcode %}
{% endtab %}

{% tab title="Sass" %}
{% code title="hello.sass" %}

```css
.greeting
    color: red
    background-color: grey[200]
    text-transform: uppercase
    padding: 10 20
```

{% endcode %}
{% endtab %}

{% tab title="Generated Dart" %}
{% code title="hello.dart" %}

```dart
Hello() {
    return DefaultTextStyle.merge(
        style: TextStyle(
            color: Colors.red
        ),
        child: Container(
            decoration: BoxDecoration(
                color: Colors.grey[200]
            ),
            padding: EdgeInsets.only(
                top: 10,
                right: 20,
                bottom: 10,
                left: 20
            ),
            child: Text("Hello world!".toUpperCase),
        )
    );
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

*Click the tabs to see the Pug code, the Sass styles we apply, and the code that flutter-view generates for you.*

Flutter-view supports [many CSS properties](/reference/css-properties), and makes it easy to change styles and immediately see the effect. Since single CSS rules can apply to many elements, small CSS changes may have big code effects.

You can also fully leverage both Pug and Sass mixin and function support, allowing for some powerful patters, such as [different styling based on running Android or iOS](/guide/untitled).

## Making it Reactive

Flutter-view does not force you into any particular Reactive model. For example it works well with streams. However, it comes with native [ScopedModel ](https://pub.dartlang.org/packages/scoped_model)support and a [small Dart support library](https://pub.dartlang.org/packages/flutter_view_tools) for terse reactive coding:

{% tabs %}
{% tab title="user.dart" %}
{% code title="user.dart" %}

```dart
class User extends Model {
    User({this.name, this.age});

    String name;
    int age;
}
```

{% endcode %}
{% endtab %}

{% tab title="hello.pug" %}
{% code title="hello.pug" %}

```c
hello(flutter-view :user)
    reactive(watch='user')
        .greeting Hello ${user.name}!
```

{% endcode %}
{% endtab %}

{% tab title="generated hello.dart" %}
{% code title="hello.dart" %}

```dart
Widget Hello({user}) {
    return ReactiveWidget(
        watch: user as Listenable,
        builder: (context, $) {
            return Container(
                child: Text("Hello ${user.name}!")
            )
        },
    );
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

The view (hello.pug) takes a User (user.dart) as a parameter and watches it for changes. Now when we change the the user name and call  `user.notifyListeners()`,  the view will automatically update.


# FAQ

## What is flutter-view

Flutter-view is a tool for creating Flutter Dart code, meant to make it easier to make trees of widgets and style them.

## How does it work?

Flutter-view itself is an [**npm**](https://www.npmjs.com) program that you run in a terminal window. It monitors your project's Pug, Sass, HTML and CSS files. When a file updates, it will create or update Dart files of the same name.

You use the Pug files to define flutter-views, which flutter-view will convert into Flutter Widget layout functions in Dart. You can them use these Dart functions in your normal Flutter code.

You can use the Sass files to add style properties to the widget trees.

For reactive programming, it uses the fantastic [**scoped\_model library**](https://pub.dartlang.org/packages/scoped_model), in combination with a new pattern where the model is passed into a view, and rendered with a ReactiveWidget. This removes the need for ScopedModel and ScopedModelDescendant, and separating the concerns of state and view. However you are also free to use other patterns, such as streams.

## How stable and complete is it?

Flutter-view is pretty much complete at this point. We have been using it at my company for half a year, and fixed many bugs and contributed features in the process. With the 1.0.0 release, it was stable, fast and fully documented. With the 2.0.0 release, null-safety is supported as well.

## Is it free? How is it licensed?

Flutter-view is completely free and open source, licensed through the[ **BSD-3 open source license**](https://github.com/flutter-view/flutter-view/blob/master/LICENSE). Please enjoy!

## Who built this and why?

Flutter-view was created by Christian Vogel. I am a software developer and entrepreneur who loves new technology. I found Flutter to have a great developer experience, but missed the clear separations of concerns and patterns that I enjoyed in frameworks like Vue.js and React. With Flutter-view I scratched my own itch, was able to use it in my company, and hope it can also help you. If you encounter any issues or have suggestions, please post an [issue on Github](https://github.com/flutter-view/flutter-view/issues), or contact me on Twitter at <http://twitter.com/christianvogel>.


# Install

*Important: going from version 2.0.0 and forward, flutter-view supports Dart 2.13 and up, enforcing null-safety. This means **breaking changes**. If you have a legacy project, stay at a version below 2.0.0, in both flutter-view and the flutter-view-widgets library which has also been updated.*

## Requirements

Flutter-view is an npm project and requires a working [NodeJS](https://nodejs.org/en/) installation. Of course you should have a working Flutter install as well.

## Installing flutter-view

To install flutter-view, run the following command in your terminal:

> `npm install -g flutter-view`

On a Mac add sudo:

> `sudo npm install -g flutter-view`

*Important: the modern version of flutter-view is for Dart 2.13 and higher, and support type safety. If you have an older project, install* `flutter-view@1.0.3` *instead.*

*Note: you may need to add **--unsafe-perm** for things to work due to an* [*issue with node-gyp*](https://github.com/nodejs/node-gyp/issues/454)

To test your installation worked, type the flutter-view command in your Terminal or console:

> `>> flutter-view`
>
> `flutter-view - flutter template code generator`  \
> `Converts html and css templates into Flutter view widget code.`  \
> `Please pass a directory to scan.`  \
> `flutter-view -h for help.`

If you got the above text, your installation was successful.

## Installing flutter-view-widgets

Flutter-view has an optional Dart tooling library. It allows you to use the reactive, assign and life-cycle tags.

### Adding the dependency

To install it, add the following dependency to your project **pubspec.yaml** file:

> `flutter_view_widgets: ^2.2.4-dev.1`

*Important: the modern version of flutter-view is for Dart 2.13 and higher, and support type safety. If you have an older project, use the following:*

> `flutter_view_widgets: 1.0.6`

Then perform a flutter packages get to pull in the new dependency.

*Note: for the latest version, check the*[ *flutter-view-widgets pub page*](https://pub.dev/packages/flutter_view_widgets/versions)*.*

### Importing the tools

To import the library in Dart:

`import 'package:flutter_view_widgets/flutter_view_widgets.dart'`

To import the library in a Pug file:

`import(package='flutter_view_widgets/flutter_view_widgets.dart')`


# Usage

The flutter-view command is:

> `flutter-view [options] <directory [, directory...]>`

Flutter-view scans for Pug and HTML files in one or more directories. For it to work, you need to pass where your source code is. Normally this is the **lib** directory of your project.&#x20;

In almost every case, you want to go to your project directory and type:

> `flutter-view -w lib`

This will tell flutter-view to watch your lib directory, and keep watching (-w) for changes.

When flutter-view creates or updates Dart files, it will tell you:

<div align="left"><img src="/files/-LSqQdhb6qenGO1TRCMz" alt=""></div>


# Test drive

To get to know how flutter-view works, let's create a little hello world example project. You can also find [this project in the examples repository](https://github.com/flutter-view/examples/tree/master/testdrive).

## Create an example flutter project

Make sure flutter-view is [installed](/get-started/installation#installation) correctly.

Open a terminal and go to where you want to create the test project:

> `cd projects-directory`

Create a new Flutter project:

> `flutter create flutter_testdrive`

Open the project in your favorite editor. [VS Code](https://code.visualstudio.com) is recommended.

Try running the test project in an emulator to see if it all works.

## Adding a screen using flutter-view&#x20;

Now that we have a working project, let's create a flutter-view that shows a simple welcome screen.

In the lib directory of your project, add a directory called "**screens**". In it create a directory "**homepage**". In the homepage directory, create a file named **homepage.pug**.

<div align="left"><img src="/files/-LSQ5zyPhu6H9QTbV52g" alt=""></div>

Now let's create our first flutter-view. Open **homepage.pug** and put in the following pug code:

{% code title="homepage.pug" %}

```css
home-page(flutter-view)
	scaffold
		app-bar(as='appBar')
			#title(as='title') Welcome
		center(as='body')
			.greeting Hello world!
```

{% endcode %}

This code will create a material Scaffold with an AppBar and put "hello world!" in the center of it.

To convert this flutter-view into Dart code, we need to run flutter-view. Go to your project directory in your command line, and type:

> `flutter-view lib`

Then check your lib/screens/homepage directory. Flutter-view should have generated homepage.dart there:

{% code title="hompage.dart" %}

```dart
// some imports

Scaffold HomePage() {
  return Scaffold( // project://lib/screens/homepage/homepage.pug#2,2
    appBar: AppBar( // project://lib/screens/homepage/homepage.pug#3,3
      title: 
      //-- TITLE ----------------------------------------------------------
      Container( // project://lib/screens/homepage/homepage.pug#4,4
        child: Text( 
          'Welcome',
        ),
      ),
    ),
    body: Center( // project://lib/screens/homepage/homepage.pug#5,3
      child: 
      //-- GREETING ----------------------------------------------------------
      Container( // project://lib/screens/homepage/homepage.pug#6,4
        child: Text( 
          'Hello world!',
        ),
      ),
    ),
  );
}

// _flatten method
```

{% endcode %}

You may notice the comments referring back to the Pug file. These can be turned off, but help the [VSCode flutter-view plugin](/get-started/vs-code-support#linking-between-pug-and-generated-dart) (and you) easily navigate between the Pug file and the Dart file.

Also, notice comments are created for **#title** and **.greeting** ids and classes in the pug file. These can also be turned off if you wish.

## Using the new homepage

A view is simply a Dart function that renders some widgets. This means you can use it in your application as any other Flutter function. Let's change **main.dart** to show our new homepage:

At the top of main.dart, import our new dart file:&#x20;

> `import 'screens/homepage/homepage.dart';`

And to use our new homepage, we need to set it as home:

```dart
// home: MyHomePage(title: 'Flutter Demo Home Page'),
home: HomePage(),
```

Now refresh your app, and you should see this:

<div align="left"><img src="/files/-LSQ6RPlX1eRKZcNRPVH" alt=""></div>

## Hot Reload

One of the powerful features in Flutter is hot reload. You can do the same thing with flutter-view.&#x20;

Start flutter-view in watch mode in your project directory:

> `flutter-view -w lib`

Now any changes you make will automatically be detected, and the Dart file will be updated. Try changing the **Hello world!** text in **homepage.pug** and press the refresh button in the emulator to see your changes.

## Adding Styling

Our homepage looks very bland, so let us add some styling.

In the same directory as **homepage.pug**, create a new file called **homepage.sass**. Let's style the .**greeting**:

{% code title="homepage.sass" %}

```css
.greeting
	color: blue
	font-size: 30
	font-weight: bold
```

{% endcode %}

Press hot refresh in your emulator and you will now see the greeting styled:

<div align="left"><img src="/files/-LSjGxu9OM_K6qYLBAay" alt=""></div>

Now let's add an image. We can choose to use a NetworkImage directly, or to use a background decoration on a container. To do the latter, we need to add the cover container for the image. Since we want to have the image and text to be centered together, we can wrap them in a [FittedBox](https://docs.flutter.io/flutter/widgets/FittedBox-class.html) widget. To do so, change **homepage.pug**:

{% code title="homepage.pug" %}

```css
home-page(flutter-view)
	scaffold
		app-bar(as='appBar')
			#title(as='title') Welcome
		center(as='body')
			fitted-box
				.cover
				.greeting Hello world!

```

{% endcode %}

Flutter-view has [shortcuts](/reference/css-properties) that recognise CSS-like properties, and transform them into code. Setting a [**background-image**](/reference/css-properties#box-shadow-1) property on a **Container** will add an [BoxDecoration](https://docs.flutter.io/flutter/painting/BoxDecoration-class.html) with a [DecorationImage](https://docs.flutter.io/flutter/painting/DecorationImage-class.html), and set it to the decoration property of that **Container**. Add the following to your **homepage.sass** and press refresh on your emulator:

```css
.cover
	width: 300
	height: 300
	background-size: cover
	background-image: url("https://cutt.ly/Gat1ivy")
```

The result should look like this:

<div align="left"><img src="/files/-LSjGZ8SD53ojyudzHYE" alt=""></div>

If you look at the generated **homepage.dart**, you will see how flutter-view took homepage.pug and homepage.sass and merged them:

{% code title="homepage.dart" %}

```dart
Scaffold HomePage() {
  return Scaffold( // project://lib/screens/homepage/homepage.pug#2,2
    appBar: AppBar( // project://lib/screens/homepage/homepage.pug#3,3
      title: 
      //-- TITLE ----------------------------------------------------------
      Container( // project://lib/screens/homepage/homepage.pug#4,4
        child: Text( 
          'Welcome',
        ),
      ),
    ),
    body: Center( // project://lib/screens/homepage/homepage.pug#5,3
      child: FittedBox( // project://lib/screens/homepage/homepage.pug#6,4
        child: Column( 
          children: __flatten([

            //-- COVER ----------------------------------------------------------
            Container( // project://lib/screens/homepage/homepage.pug#7,5
              decoration: BoxDecoration( 
                image: DecorationImage( 
                  image: NetworkImage( 
                    'https://cutt.ly/Gat1ivy',
                  ),
                  fit: BoxFit.cover,
                ),
              ),
              width: 300,
              height: 300,
            ),
            DefaultTextStyle.merge( 
              child: 
              //-- GREETING ----------------------------------------------------------
              Container( // project://lib/screens/homepage/homepage.pug#8,5
                child: Text( 
                  'Hello world!',
                ),
              ),
              style: TextStyle( 
                fontSize: 30,
                color: Colors.blue,
                fontWeight: FontWeight.bold,
              ),
            )
          ]),
        ),
      ),
    ),
  );
}
```

{% endcode %}

Feel free to play around with some CSS styles to see effect. Some of the things you could try:

* add [**margin**](/reference/css-properties#margin) between the cover image and the greeting by adding `margin-top: 10` to the .greeting class in **homepage.sass**.
* instead of a background image, give the **.cover** class a `background-color: blue`.

Currently you need to press the hot refresh button in your emulator to see changes. In the next section we add Visual Studio Code support so this will happen immediately when you change your .pug or .sass file.


# VS Code support

You can use flutter-view with any IDE. However for Visual Studio Code users there are tools to make life more convenient.

## Linking between Pug and generated Dart

<div align="left"><img src="/files/-LSWk9Sr1D58U4AoLNvE" alt="Command-clicking between Pug and Dart code in VS Code"></div>

Enabling linking between Pug and Dart will make it easier to see the effects of your changes. To get this functionality in VSCode, install the following two extensions:

* the [**flutter-view extension**](https://marketplace.visualstudio.com/items?itemName=blueneogeo.flutter-view-vscode) lets you link from Pug to generated Dart
* the [**project-links extension**](https://marketplace.visualstudio.com/items?itemName=KyleDavidE.vscode-project-links) lets you link from links in the generated Dart to the source Pug

*Note: for this to work, the project link comments in flutter-view must be enabled (default is on)*

## Enabling hot refresh for Pug and Sass files

Normally when you change Flutter Dart code in VSCode, the Dart extension knows you are running a Flutter project and triggers a hot reload in your connected device or emulator.

When you change a Pug or Sass file, flutter-view will update the Dart code in the background as you save. However the editor will not know that it needs to trigger a hot reload.

To enable this, we need to do two things:

1. install the [save and run ext](https://github.com/padjon/vscode-save-and-run-ext) extension that lets us trigger commands on events on saving
2. add the commands to hot-reload when the files are saved.

### Adding the hot reload commands

After installing the extension, press `cmd+shift+P` to open the command palette in VSCode and pick the **Preferences: Open Settings (JSON)** command to open your settings.

In the **JSON settings** under either *Workspace settings* or *User settings*, add the following extra configuration:

```javascript
"saveAndRunExt": {
        "commands": [
            {
                "match": ".pug",
                "isShellCommand" : false,
                "cmd": "flutter.hotReload"
            },
            {
                "match": ".sass",
                "isShellCommand" : false,
                "cmd": "flutter.hotReload"
            },
            {
                "match": ".css",
                "isShellCommand" : false,
                "cmd": "flutter.hotReload"
            },
            {
                "match": ".html",
                "isShellCommand" : false,
                "cmd": "flutter.hotReload"
            },
            {
                "match": ".htm",
                "isShellCommand" : false,
                "cmd": "flutter.hotReload"
            }
        ]
    },
```

Your settings should like something like this:

![](/files/-LSeLRtwAgs8dknJ-R75)

Save your settings afterwards.

### Testing the hot reload

Now try opening the test drive project from the previous chapter (or your own flutter-view project) and run it in the emulator.

Changing the Pug or Sass and saving it should now automatically make the changes visible in your running application.

Congratulations, you are all ready to start making your flutter-view enabled Flutter app!


# Examples

Examples can help to show some good patterns for creating elegant apps. These are currently available:

### [Testdrive](https://github.com/flutter-view/examples/tree/master/testdrive)

<div align="center"><img src="/files/-LSjGZ8SD53ojyudzHYE" alt=""></div>

This is the **getting started project** as explained in the[ test drive chapter](/get-started/test-drive) of the documentation. It shows a simple hello world using pug and sass.

### [Counter](https://github.com/flutter-view/examples/tree/master/counter)

![](/files/-LSlCnKhlmxhF5InILuI)

A flutter-view version of the Flutter starter project. It uses the **reactive** tag and the [flutter-view-tools library ](https://pub.dartlang.org/packages/flutter_view_tools)for responding and updating the count.

Instead of having the counter state in the widgets, it is kept in the application model, and the HomePage flutter-view listenes to the model and updates itself when the user presses the + button.

### [Todolist](https://github.com/flutter-view/examples/tree/master/todolist)

![](/files/-LSlCnKfJHe19culk9cY)

An example of how you can build a simple todo app using flutter-view and the [flutter-view-tools library](https://pub.dartlang.org/packages/flutter_view_tools). It separates the app model from the page model. This is a structure that can scale as your app grows and you add more pages. The [Writing Reactive code](/guide/writing-reactive-code) chapter builds this app step by step.


# Configuring flutter-view

**Flutter-view does not need a configuration file to run.** However by providing a configuration, you can use some more advanced features.

To configure flutter-view, put a file named **flutter-view\.json** in the directory you run it from (normally your project root directory). The options you can set are described below. Each of these options is optional. Options will merge their values with the ones you provides.

For example, to change the indentation of the generated Dart to 4 spaces:

{% code title="flutter-view\.json" %}

```javascript
{
    indentation: 4
}
```

{% endcode %}

## indentation

Changes the indentation of the generated Dart files.

Default value:

```javascript
indentation: 2
```

## ignores

Starting from flutter-view 2.0.0, instead of having error ignore statements generated per line, each view will have a couple of ignore statements at the top for the whole file. You can add your own. By default these are:

```javascript
ignores: [
    // const is not always detectable, so by default suppress the errors
    'prefer_const_constructors',
    'non_constant_identifier_names',
    // we sometimes do unnecessary code but it should not cause performance issues
    'unnecessary_import',
    'dead_code',
    'unused_element',
    'unnecessary_cast',
    'unnecessary_string_interpolations',
    'invalid_null_aware_operator',
    // for now we use these because classes create containers and we want them to be styleable
    // later we may be able to detect if we have styles and use Nil and SizedBox containers where possible
    'avoid_unnecessary_containers',
    'sized_box_for_whitespace'
]
```

## imports

Lets you provide a list of imports to add in every generated Dart file. This can save you from having to add the same import statement at the top of your files.

Default value:

```javascript
imports: [
	'package:flutter/material.dart',
	'package:flutter/cupertino.dart'
]
```

For example, to add the[ **flutter\_view\_widgets**](https://pub.dev/packages/flutter_view_widgets) to each file:

{% code title="flutter-view\.json" %}

```javascript
{
    imports: [
        "package:flutter_view_widgets/flutter_view_widgets.dart"
    ]
}
```

{% endcode %}

## tagClasses

Lets you map how certain tags are mapped into Dart classes. For example, by default a DIV is mapped into a Container.

Default value:

```javascript
tagClasses: {
	text: 'Text',
	div: 'Container',
	span: 'Wrap',
	button: 'RaisedButton',
	backgroundAssetImg: 'ExactAssetImage',
	backgroundUrlImg: 'NetworkImage'
}
```

For example, if you want to use FlatButton when you use the button tag:

{% code title="flutter-view\.json" %}

```javascript
{
    tagClasses: {
        button: "FlatButton"
    }
}
```

{% endcode %}

## multiChildClasses

In Flutter, some widgets expect a child parameter, while others expect a children parameter. With multiChildClasses you can list classes that require the children parameter (otherwise child is used).

Note: in case an entry is not in the default list, you can also pass the children via the array tag. For example:

```css
column
    array(as='children')
        row first child
        row second child
```

Default values:

```javascript
multiChildClasses: [
	'Row',
	'Column',
	'Stack',
	'IndexedStack',
	'GridView',
	'Flow',
	'Table',
	'Wrap',
	'ListBody',
	'ListView',
	'CustomMultiChildLayout'
]
```

## autowrapChildren and autoWrapChildrenClass

In HTML layouts, any element can have multiple children. However in Flutter, some widgets accept only a single child.&#x20;

If autowrapChildren is set to false, only the first child is set.&#x20;

If autowrapChildren is set to true, the children are wrapped by a widget that accepts multiple children. The widget used is set in the autowrapChildrenClass property.

The default values:

```javascript
autowrapChildren: true,
autowrapChildrenClass: 'Column'
```

## showPugLineNumbers

If set to true, flutter-view will add comments to the Dart file that link back to the original pug files. These comments are [used by the VSCode extensions](/get-started/vs-code-support#linking-between-pug-and-generated-dart) to provide easy navigation between the two.

The comments look like this:

`Container( // project://lib/screens/queue/queue.pug#19,6`

Default value:

```javascript
showPugLineNumbers: true
```

## showCommentsInDart

If true, flutter-view will add comments in Dart based on the classes and ids that you assign to tags in the Pug or HTML.

For example, the following Pug code:

```css
#title(as='title') Tasks
```

Will add the #title as a comment:

```dart
//-- TITLE ----------------------------------------------------------
Container(
    child: Text( 
        'Tasks',
    ),
)
```

By setting showCommentsInDart to false, this feature is disabled.

Default value:

```javascript
showCommentsInDart: true
```

## reportErrorsInDart

If set to true, if there is an error processing a pug or css file, the error will not only be printed by flutter-view in the console, but also be shown as text in the Dart file.

The benefit of this is that if you make a Pug or Sass mistake, it will show as an error in your IDE, instead of just in the flutter-view output.

Default value:

```javascript
reportErrorsInDart: true
```

## propagateDelete

If true, when you delete a pug file, the asociated Dart file also gets deleted.

Default value:

```javascript
propagateDelete: true
```


# Creating a new view

To create a new view, create a Pug file. It is common to put this file in its own directory with the same name, to group the page, styling and optional models together. A single page can contain many flutter-views.

## Importing Dart dependencies

### Default imports

By default, the following imports are added to  generated Dart files:

```dart
import 'package:flutter/material.dart'
import 'package:flutter/cupertino.dart';
```

You can [add additional default imports](/guide/configuring-flutter-view#imports) using **flutter-view\.json**.

### Adding imports

To import additional packages in a Pug or HTML file, use the import tag with the package parameter:

{% tabs %}
{% tab title="Pug" %}

```css
import(package='flutter_view_widgets/flutter_view_widgets.dart')
```

{% endtab %}
{% endtabs %}

To import files in a Pug or HTML file, use the import tag with the file parameter. The files are relative to the current file directory:

{% tabs %}
{% tab title="Pug" %}

```css
import(file='../directory/test.dart')
```

{% endtab %}
{% endtabs %}

## Creating Flutter-views

A flutter-view is transformed into a Dart function. As such, you are just writing Dart functions in an HTML-like format.

### Method body

The format of a flutter view in Pug is as follows:

{% tabs %}
{% tab title="Pug" %}

```pug
method-name(flutter-view [optional parameters])
    ...method body...
```

{% endtab %}
{% endtabs %}

This will render into the following Dart:

```dart
MethodName([optional parameters]) {
    return ...method body...
}
```

The method name in HTML or Pug is dash-cased, and gets transformed into camel-case. The same is true for the parameters.

Note: The generated Dart functions start in uppercase. This is so they can be called from other flutter-views, as will become clear in a moment.

### Adding Parameters

Parameters are defined as follows:

`:parameter-name[type]?`

The **\[type]** and **?** are optional:

* The type becomes the type of the parameter in the Dart function. If omitted, it it is considered dynamic
* By default, parameters you specify are required. Adding a **?** at the end indicates that they are optional.

Example:

{% tabs %}
{% tab title="Pug" %}

```pug
task-list-item(flutter-view :task-model[TaskList] :task[Task] :done?)
    ...widgets that show the task...
```

{% endtab %}
{% endtabs %}

This will render into the following Dart:

```dart
TaskListItem({ @required TaskList taskModel, @required Task task, done) {
    return ...widgets that show the task..
}
```


# Creating widget layouts

## Overview

In Flutter, widget trees are built by passing a child or children. Widget trees have a lot of indentation, especially since in Flutter nearly everything is a widget, and composition is preferred to inheritance. This can lead to complex nesting and child parameters.

Flutter-views are optimised for building widget trees. Pug in particular is well suited for creating tree structures and moving parts around.

The following example generates a Dart method **FooPage()**, which returns a Scaffold with an AppBar, and a centralized greeting message.&#x20;

The Pug creates the layout, and the main.dart file uses this layout to render the app. This separation between layout and logic is fundamental to using flutter-view.

{% tabs %}
{% tab title="Pug" %}
{% code title="foo-page.pug" %}

```pug
foo-page(flutter-view :greeting)
    scaffold
        app-bar(as='appBar')
            container(as='title') Foo Page
        center(as='body') Hello $greeting!
```

{% endcode %}
{% endtab %}

{% tab title="generated Dart" %}
{% code title="foo-page.dart" %}

```dart
FooPage({@required greeting}) {
    return Scaffold(
        appBar: AppBar(
            title: Container(
                child: Text('Foo page'),
            ),
        ),
        body: Center(
            child: Text('Hello $greeting!'),
        ),
    );
}
```

{% endcode %}
{% endtab %}

{% tab title="main.dart" %}
{% code title="main.dart" %}

```dart
import 'package:flutter/material.dart';
import 'foo-page.dart';

void main() => runApp(TestApp());

class TestApp extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Test App',
      home: FooPage(greeting: 'world!')
    );
  }

}
```

{% endcode %}
{% endtab %}
{% endtabs %}

## Adding children to widgets

**In a flutter-view, add indented child tags to tags to automatically have them assigned as child or children parameters**.

In flutter-view Pug/HTML content, an HTML **tag** is a **method or constructor call**, and its parameters are parameters for this method or constructor. The tag **children** are assigned as the Flutter child/children **parameters**.

To see how this works, compare the Pug and generated Dart code in this example:

{% tabs %}
{% tab title="Pug" %}

```pug
container
    column
        row 
            text(value='first row!')
        row 
            text(value='second row!')
        row
            flat-button 
                text(value='Click me!')
            
```

{% endtab %}

{% tab title="generated Dart" %}

```dart
return Container(
    child: Column(
        children: [
            Row(
                children: [
                    Text('first row!'),
                ],
            ),
            Row(
                children: [
                    Text('second row!'),
                ],
            Row(
                FlatButton(
                    child: Text('Click me!'),
                )
            ),
        ],
    ),
);
```

{% endtab %}
{% endtabs %}

### Automatic columns

Flutter-view knows which classes generally need children instead of single child, and automatically creates [**Columns**](https://docs.flutter.io/flutter/widgets/Column-class.html) when you pass multiple children. Also, if you pass text, flutter-view it automatically wraps it in a [**Text**](https://docs.flutter.io/flutter/widgets/Text-class.html) widget as well. This together allows you to be more terse:

{% tabs %}
{% tab title="Pug" %}

```pug
container
    row first row!
    row second row!
    row
        flat-button Click me!            
```

{% endtab %}

{% tab title="generated Dart" %}

```dart
return Container(
    child: Column(
        children: [
            Row(
                children: [
                    Text('first row!'),
                ],
            ),
            Row(
                children: [
                    Text('second row!'),
                ],
            Row(
                FlatButton(
                    child: Text('Click me!'),
                )
            ),
        ],
    ),
);
```

{% endtab %}
{% endtabs %}

You can [override the default wrapper](/guide/configuring-flutter-view#autowrapchildren-and-autowrapchildrenclass) in **flutter-view\.json**.

### Calling dart factory constructors

Some Flutter Dart classes may use factory constructors. For example, ButtonTheme has a [**ButtonTheme.bar()**](https://docs.flutter.io/flutter/material/ButtonTheme/ButtonTheme.bar.html) constructor.&#x20;

To call the factory constructor instead of the default constructor, pass the constructor after the class name, separated with a colon.

{% tabs %}
{% tab title="Pug" %}

```pug
button-theme:bar
    | some content here
```

{% endtab %}

{% tab title="generated Dart" %}

```dart
ButtonTheme.bar(
    child: Text(
        'some content here'
    ),
)
```

{% endtab %}
{% endtabs %}

### Passing children instead of child

There may be cases where flutter-view does not recognise your tag needs a children parameter instead of a child parameter. In that case use and array and assign it as children:

{% tabs %}
{% tab title="Pug" %}

```pug
column
    array(as='children')
        row first!
        row second!
```

{% endtab %}

{% tab title="generated Dart" %}

```dart
Column(
    children: [
        Row(
            children: [
                Text('first!'),
            ]
        ),
        Row(
            children: [
                Text('second!'),
            ]
        ),
    ]
)
```

{% endtab %}
{% endtabs %}

### Passing const widgets

For optimising performance, you may want to pass some widgets as constants. You can do this by adding a **const** parameter in a widget:

To see how this works, compare the Pug and generated Dart code in this example:

{% tabs %}
{% tab title="Pug" %}

```pug
container
    column(const)
        row 
            text(value='first row!')
```

{% endtab %}

{% tab title="generated Dart" %}

```dart
return Container(
    child: const Column(
        children: [
            Row(
                children: [
                    Text('first row!'),
                ],
            ),
        ],
    ),
);
```

{% endtab %}
{% endtabs %}

## Passing parameters

To pass parameters besides child or children, you pass them as pug/html parameters.

### String parameters

You can pass strings by using quotes. Both double and single quotes work.

For example:

{% tabs %}
{% tab title="Pug" %}

```pug
banner(title='testing')
    | Hello world!
```

{% endtab %}

{% tab title="generated Dart" %}

```dart
return Banner(
    title: 'testing',
    child: Text('Hello world!'),
);
```

{% endtab %}
{% endtabs %}

### Expression parameters

To assign a Dart expression as the value of a parameter:

* start the parameter name with `:`
* wrap the expression in quotes. You may need to escape strings.

For example:

{% tabs %}
{% tab title="Pug" %}

```pug
flat-button(:color='highlighted ? Colors.red : Colors.grey')
    | Click me!     
```

{% endtab %}

{% tab title="generated Dart" %}

```dart
return FlatButton(
    color: highlighted ? Colors.red : Colors.grey,
    child: Text('Click me!'),
);
```

{% endtab %}
{% endtabs %}

For **title** we want to pass a direct string, but for **color** we want to pass a value by reference, so we add **:** in front of the parameter.

### Unnamed parameters

Some widgets take an unnamed parameter in their constructor. You can pass this using the reserved **value** parameter:

{% tabs %}
{% tab title="Pug" %}

```pug
container
    icon(:value='Icons.add')
    text(value='Hello world')
```

{% endtab %}

{% tab title="generated Dart" %}

```dart
return Container(
    child: Column(
        children: [
            Icon(Icons.add),
            Text('Hello world'),
        ]
    ),
);
```

{% endtab %}
{% endtabs %}

### Escaping parameter names

You may need to pass a parameter that has the name of a reserved keyword, such as value. You can bypass this problem by escaping your parameter with the ^ sign:

```
:^value='foo'
```

### Passing complex parameter values

Sometimes what you want to pass is not just a single value, but a value that is constructed of many widgets. To solve this, you may take a child and use the **as** keyword to assign it as a parameter to the parent widget.

{% tabs %}
{% tab title="Pug" %}

```pug
scaffold
    app-bar(as='appBar')
        container(as='title') Test App
    center(as='body') Hello world!
```

{% endtab %}

{% tab title="generated Dart" %}

```dart
return Scaffold(
    appBar: AppBar(
        title: Container(
            child: Text('Test App'),
        ),
        body: Center(
            child: Text('Hello world!'),
        ),
    ),
);
```

{% endtab %}
{% endtabs %}

The [Scaffold](https://docs.flutter.io/flutter/material/Scaffold-class.html) class used above has no child or children parameters. Instead we add two children and assign them as parameters using the **as** property.

### Passing functions as children

You can create functions that return children using the [**function shortcut**](/reference/tag-shortcuts#function).

### Passing handlers

Passing a handler function or closure is no different than in Dart:

```pug
my-button(flutter-view :on-click[Function])
    flat-button(:on-pressed='onClick') Click me!
```

A common case is a closure without any parameters. In that case you can use the @ sign to create a closure handler:

{% tabs %}
{% tab title="Pug" %}

```pug
my-button(flutter-view)
    flat-button(@on-pressed='print("Click!")') Click me!
```

{% endtab %}

{% tab title="generated Dart" %}

```dart
MyButton() {
    return FlatButton(
        onPressed: () { print("Click!"); },
        child: Text('Click me!'),
    );
}
```

{% endtab %}
{% endtabs %}

### Passing Arrays

Sometimes you need to pass an array of specific items to a parameter. In that case you can use the **array** tag.

{% tabs %}
{% tab title="Pug" %}

```pug
custom-scroll-view
    array(as='slivers')
        sliver1
        sliver2
        sliver3
```

{% endtab %}

{% tab title="generated Dart" %}

```dart
CustomScrollView(
    slivers: [
        sliver1,
        sliver2,
        sliver3,
    ],
)
```

{% endtab %}
{% endtabs %}

## Automatic Containers

A nice Pug feature is that classes and ids are automatically converted into DIV tags. In flutter-view, they are automatically converted into [Container](https://docs.flutter.io/flutter/widgets/Container-class.html) widgets:

```pug
container hello world
#greeting hello world
.greeting hello world
```

All three are equivalent and convert to:

```dart
Container(
    child: Text('hello world'),
)
```

The classes and ids you use are forgotten after the conversion to Dart code. However, you do get automatic commenting, which will make it easier to read the generated code.

The biggest benefit is however that you can use them to style your widgets.


# Flow control

In your views you often want to only conditionally show something, or loop through a list of items. For this flutter-view has some intentionally simple flow control keywords.

## if

This will only render the widget if the passed condition is true.

{% tabs %}
{% tab title="Pug" %}

```pug
user-profile(flutter-view :user[User])
    .user
        .name ${user.name}
        .company(if='user.company != null') Works at ${user.company}
```

{% endtab %}

{% tab title="generated Dart" %}

```dart
UserProfile({required User user}) {
    return Container(
        child: Column(
            children: [
                Container(
                    child: Text('${user.name}'),
                ),
                user.company != null ?
                Container(
                    child: Text('Works at ${user.company}'),
                ) 
                : SizedBox(),
            ],
        ),
    );
}
// left out some flatten operations for simplicity
```

{% endtab %}
{% endtabs %}

In the above example, the company will only be shown if the passed user has the company property set.

## if-null

This will only render the widget if the passed condition is false, otherwise it returns null.

With type and null-safety in Dart, you sometimes need to either pass an argument or null. The normal `if` above will return a `SizedBox()` if the condition fails. For building widget trees, this is usually makes sense. However sometimes we need to pass an argument that can be null, depending on a condition. In these edge cases, use `if-null.`

{% tabs %}
{% tab title="Pug" %}

```pug
app-bar
    .title(as='title' null-if='user.name == null') ${user.name}
```

{% endtab %}

{% tab title="generated Dart" %}

```dart
PlatformAppBar(
  title: !(name == null) ?
    Container(
      child: Text(
        '${name}',
      ),
    ) : null,
)
```

{% endtab %}
{% endtabs %}

In the above example, the title of the `AppBar` widget will be set to null if the `user.name` is `null`.

## slot

A slot is a placeholder for a value. It will take the value of the first valid child. Alternatively, you can also directly pass a value into it:

{% tabs %}
{% tab title="Pug" %}

```pug
wrapper(flutter-view :content[Widget])
    slot(:value='content').content
    .footer A footer
```

{% endtab %}

{% tab title="Generated Dart" %}

```dart
Column Wrapper({ required Widget content }) {
  return Column( 
    children: __flatten([
      content,
      //-- FOOTER ----------------------------------------------------------
      Container(
        child: Text( 
          'A footer',
        ),
      )
    ]),
  );
}
```

{% endtab %}
{% endtabs %}

Slot can function as an if/else. In the next example you see either the .status being shown, or the .empty.

{% tabs %}
{% tab title="Pug" %}

```pug
tasks-page(flutter-view :tasks[List])
    scaffold
        slot(as='body')
            .status(if='tasks.isNotEmpty') You have ${tasks.length} tasks
            .empty You have no tasks yet...

```

{% endtab %}

{% tab title="generated Dart" %}

```dart
Scaffold TasksPage({ required List tasks }) {
  return Scaffold(
    body: (tasks.isNotEmpty) ?
      //-- STATUS ----------------------------------------------------------
      Container(
        child: Text( 
          'You have ${tasks.length} tasks',
        ),
      ):
    true ?
      //-- EMPTY ----------------------------------------------------------
      Container(
        child: Text( 
          'You have no tasks yet...',
        ),
      )
    : Container(),
  );
}

```

{% endtab %}
{% endtabs %}

As you can see in the above example, you can use the **as** property to assign the slot value to a parameter as well. In this case, the content of the slot is placed in the body parameter of the Scaffold.

By adding multiple children with if to a slot, you can also create a switch/case:

{% tabs %}
{% tab title="Pug" %}

```pug
slot
    .apple(if='fruit=="Apple"')
    .pear(if='fruit=="Pear"')
    .peach(if='fruit=="Peach"')
    .unknown // the fallback

```

{% endtab %}
{% endtabs %}

## for

Use **for** to repeat a widget for every value in a list. For every repetition, the value gets assigned to a variable, which you can use to render the widget and its children.

{% tabs %}
{% tab title="Pug" %}

```pug
tasks-page(flutter-view :tasks[List])
    scaffold
        slot(as='body')
            .task(for='task in tasks')
                .title ${task.title}
                .description ${task.description}
```

{% endtab %}

{% tab title="generated Dart" %}

```dart
Scaffold TasksPage({ required List tasks }) {
  return Scaffold(
    body: 
    //-- BODY ----------------------------------------------------------
    Container(
      child: (tasks as List).map((task) {
        return
        //-- TASK ----------------------------------------------------------
        Container(
          child: Column( 
            children: [
              //-- TITLE ----------------------------------------------------------
              Container(
                child: Text( 
                  '${task.title}',
                ),
              ),
              //-- DESCRIPTION ----------------------------------------------------------
              Container(
                child: Text( 
                  '${task.description}',
                ),
              )
            ]),
          ),
        );
      }).toList(),
    ),
  );
}
```

{% endtab %}
{% endtabs %}

You can also get the index (starting at 0) of the current entry as such:

```c
.task(for='task, index in tasks')
```


# Shortcuts

Flutter-view supports special macro-like shortcut tags and properties, that are meant to let you easily lay out code and allow for CSS-like styling.&#x20;

See the shortcuts reference for a list of all included shortcuts.

## Shortcut tags

The shortcut tags are macros that help you code layouts more easily.&#x20;

For example, the [**builder**](/reference/tag-shortcuts#builder) tag is a shortcut to a [**Builder**](https://docs.flutter.io/flutter/widgets/Builder-class.html) widget with a build function, so you do not need to write the function. You simply keep writing widgets as its children.

Other notable examples are:

* [**reactive**](/reference/tag-shortcuts#reactive): lets you write terse reactive code that responds to your model changes

See the [**shortcut tags reference**](/reference/tag-shortcuts) for all tags.

## Shortcut properties

The shortcut properties are macros that insert common layout behaviour that take more code in Flutter, such as easily setting a background color to a container or adding text styling. These properties are as much as **CSS** properties as possible. However when there is no direct CSS-like analogy, the **Flutter** names and values are used. They are in **dash case**, since camelcase is not officially supported.

You can also place these properties in a separate CSS or Sass file. This allows you to separate your styling from your structure, as you would in HTML and CSS.

Some commonly used examples are:

* [**margin**](/reference/css-properties#margin) and [**padding**](/reference/css-properties#padding) to let you lay out code easily
* [**background-image**](/reference/css-properties#box-shadow-1)**,** [**background-color**](/reference/css-properties#box-shadow-2) and [**border-radius**](/reference/css-properties#border-radius) to style containers
* [**font-size**](/reference/css-properties#box-shadow-8)**,**[ **font-family**](/reference/css-properties#box-shadow-10) and [**font-weight**](/reference/css-properties#box-shadow-9): to style text
* any property name ending on [**color**](/reference/css-properties#color-color) accepts both color names and hex codes

See the [**shortcut properties reference**](/reference/css-properties) for all supported properties.

### Escaping property shortcut processing

If you have to pass a parameter which has the name of a shortcut, and you do not wish to apply the shortcut, you can escape it with the ^ character.

For example, by default the [**fit** property](/reference/css-properties#fit) takes a BoxFit name. For example:

`box-decoration(fit="cover")`

However if you have a situation where you have a widget that happens to have the fit property as well, but do not want flutter-view to processes it as a BoxFit value, you can escape the property:

`my-widget(:^fit="someValue")`


# Styling with CSS

## Overview

One of the most powerful features in flutter-view is that it allows you to use CSS styles to flutter widgets, and to set any property of any flutter widget.

For example, you can start with a simple Container:

```pug
greeting(flutter-view)
    .example Hello world!
```

This will generate a function that returns a Container with the class name "example", that in turns contains a Text widget with the text "Hello world".

Then you can style this Container by assigning Sass styles to the class:

```sass
.example
    width: 500
    height: 300
    color: red
    background-color: #333
    font-size: 20
    font-weight: bold
```

Flutter-view will process your styles, attaching them to the classes. Properties such as width and height are directly assigned. Some properties are recognized as CSS properties, and generate more code, such as color and font-size. The result is a normal Dart function you can call in your normal Dart code to render the styled view. In this case, a grey box with red bold text saying "Hello world!".

## Structuring your files for styling

**You can use CSS or Sass to set any property to any class or id in your Pug or HTML file.**

To style a Pug file, create a Sass style file with the same name (but different extension) as your Pug file, in the same directory. For example, if you have a startpage.pug, to style it simply add a startpage.sass in the same directory.

*Recommendation*: create a directory per layout, with the name of your layout. Then inside, create a pug file, sass file and your model and other supporting files.

Example structure:

<div align="left"><img src="/files/-LTgzCHcEBuccosXNgLo" alt=""></div>

See the[ example projects](/get-started/examples) for more ideas for structuring your application.

## Applying styles as properties

**You can apply extra properties to html elements by adding them through style rules.**

To style anything in a flutter-view you:

1. add classes to the elements in your pug file,
2. add style rules to these classes in the related sass file

To assign a class in pug, use the  [Pug .classname syntax](https://pugjs.org/language/attributes.html#class-literal). Any div element becomes a Container widget.

For example, given the following Pug:

```c
.message hello!
```

This will translate into the following HTML:

```markup
<div class="message">hello!</div>
```

You can then use the `.message` class to assign properties using Sass or CSS:

```sass
.message
    width: 200
    height: 200
```

The resulting Dart will be a combination of your layout and style:

```dart
Container(
  child: Text( 
    'hello!',
  ),
  width: 200,
  height: 200,
);
```

## Using shortcut properties in styles

**Flutter-view provides many shortcut properties, that let you style in a CSS-style manner.**

Some examples are [color](/reference/css-properties#color-color), [padding](/reference/css-properties#padding), [margin](/reference/css-properties#margin) and [background-image](/reference/css-properties#box-shadow-1). See the [shortcut properties reference](/reference/css-properties) for the full list.

As an example, consider the following Pug layout we want to style (taken and converted into flutter-view Pug from the [Flutter Card sample](https://docs.flutter.io/flutter/material/Card-class.html)):

```pug
card
    column
        list-tile
            icon(as='leading' :value='Icons.album')
            .title(as='title') The Enchanted Nightingale
            .subtitle(as='subtitle') Music by Julie Gable. Lyrics by Sidney Stein.
        button-theme:bar
            button-bar
                flat-button.tickets(@on-pressed='...')
                    .label Buy tickets
                flat-button.listen(@on-pressed='...')
                    .label Listen
```

We have a layout, and now we can style it.&#x20;

The "buy tickets" and "listen" FlatButtons we want to have uppercase text. We can use the [**text-transform**](/reference/css-properties#box-shadow-18) shortcut:

```pug
flat-button
    .label
        text-transform: uppercase
```

We want the card to be blue and the column of the card to have `mainAxisSize: MainAxisSize.min`:. Here we can use the [**color**](/reference/css-properties#color-color) shortcut, so we can use CSS colors, and the [**main-axis-size**](/reference/css-properties#box-shadow-7) shortcut, which lets us simply use 'min':

```pug
card
    color: blue
    column
        main-axis-size: min
```

We want to give some padding to the title and subtitle, and give each slightly different colors. [**Padding**](/reference/css-properties#padding) and [**margin**](/reference/css-properties#margin) are shortcuts that adhere to CSS standards:

```pug
card
    list-tile
        .title
            color: white
            padding: 4 6
        .subtitle
            color: grey[100]
            padding: 2 6
```

Here is the end result:

![](/files/-LThE8tftoAGnkjQI66K)

{% tabs %}
{% tab title="artist-card.pug" %}

```pug
artist-card(flutter-view :on-buy-pressed :on-listen-pressed)    
    card
        column
            list-tile
                icon(as='leading' :value='Icons.album')
                .title(as='title') The Enchanted Nightingale
                .subtitle(as='subtitle') Music by Julie Gable. Lyrics by Sidney Stein.
            button-theme:bar
                button-bar
                    flat-button.tickets(@on-pressed='onBuyPressed()')
                        .label Buy tickets
                    flat-button.listen(@on-pressed='onListenPressed()')
                        .label Listen
```

{% endtab %}

{% tab title="artist-card.sass" %}

```sass
card
    color: blue
    column
        main-axis-size: min
    list-tile
        .title
            color: white
            padding: 4 6
        .subtitle
            color: grey[100]
            padding: 2 6
        flat-button
            .label
                text-transform: uppercase
```

{% endtab %}

{% tab title="generated artist-card.dart" %}

```dart
Card ArtistCard({ @required onBuyPressed, @required onListenPressed }) {
  return Card(
    child: Column(
      children: [
        ListTile(
          leading: Icon(
            Icons.album,
            color: Colors.white,
          ),
          title: DefaultTextStyle.merge( 
            child: 
            //-- TITLE ----------------------------------------------------------
            Container(
              child: Text( 
                'The Enchanted Nightingale',
              ),
              padding: EdgeInsets.only(top: 4, right: 6, bottom: 4, left: 6),
            ),
            style: TextStyle( 
              color: Colors.white,
            ),
          ),
          subtitle: DefaultTextStyle.merge( 
            child: 
            //-- SUBTITLE ----------------------------------------------------------
            Container(
              child: Text( 
                'Music by Julie Gable. Lyrics by Sidney Stein.',
              ),
              padding: EdgeInsets.only(top: 2, right: 6, bottom: 2, left: 6),
            ),
            style: TextStyle( 
              color: Colors.grey.shade300,
            ),
          ),
        ),
        ButtonTheme.bar(
          child: ButtonBar(
            children: [

              //-- TICKETS ----------------------------------------------------------
              FlatButton(
                onPressed: () { onBuyPressed(); },
                child: DefaultTextStyle.merge( 
                  child: 
                  //-- LABEL ----------------------------------------------------------
                  Container(
                    child: Text( 
                      'Buy tickets'.toUpperCase(),
                    ),
                  ),
                  style: TextStyle( 
                    color: Colors.white,
                  ),
                ),
              ),

              //-- LISTEN ----------------------------------------------------------
              FlatButton(
                onPressed: () { onListenPressed(); },
                child: DefaultTextStyle.merge( 
                  child: 
                  //-- LABEL ----------------------------------------------------------
                  Container(
                    child: Text( 
                      'Listen'.toUpperCase(),
                    ),
                  ),
                  style: TextStyle( 
                    color: Colors.white,
                  ),
                ),
              )
            ],
          ),
        )
      ]),
      mainAxisSize: MainAxisSize.min,
    ),
    color: Colors.blue,
  );
}
```

{% endtab %}
{% endtabs %}

As you can see here, Sass is a nice match with Pug, since you can retain the same structure. This makes it easy to find the matching styles to your pug elements.

## Setting expressions

**You can set an expression in CSS by wrapping the expression in quotes and starting it with a colon.**

It is recommended to keep Dart expressions in your Pug files. However, in some cases it can be practical to be able to set an expression as a CSS value, for example if flutter-view does not have special support for it.

Say you want to achieve the following Dart:

```dart
Table( 
    defaultVerticalAlignment: TableCellVerticalAlignment.middle,
    children: [ ... ]
)
```

Which you can achieve with the following (a bit contrived) Pug code:

```pug
table(:default-verticle-alignment='TableCellVerticalAlignment.middle')
    ...children...
```

Now let's move the `defaultVerticleAlignment` property into a Sass file:

{% tabs %}
{% tab title="Sass" %}

```css
table
    default-verticle-alignment: ':TableCellVerticalAlignment.middle'
```

{% endtab %}

{% tab title="Pug" %}

```css
table
    ...children...
```

{% endtab %}
{% endtabs %}

Note the colon before `TableCellVerticleAlignment.middle`in the Sass file.

## Using Flutter Themes in styles

Flutter's Material library has [theming support](https://flutter.io/docs/cookbook/design/themes). You may want to assign the values of the theme of the current BuildContext. Flutter-view has support for easily assigning [**ThemeData**](https://docs.flutter.io/flutter/material/ThemeData-class.html) values to your properties.

To understand how it works, let's first look at how you would use it in pure Dart code. To assign a font size to a style, you may write something like this:

```dart
style: TextStyle( 
  fontSize: Theme.of(context).textTheme.title.fontSize,
)
```

First we find the Theme of the current [**BuildContext**](https://docs.flutter.io/flutter/widgets/BuildContext-class.html), then we get a path of properties.

In flutter-view CSS, you might write this the same way:

```sass
.foo
    font-size: ':Theme.of(context).textTheme.title.fontSize'
```

Instead, you may write it like this:

```sass
.foo
    font-size: theme(text-theme/title/font-size)
```

This still requires the context to be available. If you have no current context, you can use the [**builder shortcut**](/reference/tag-shortcuts#builder). The theme properties path has been replaced by dash-cased steps, separated by forward slashes`/`.

*Pro tip: You can define CSS classes that set multiple theme style properties at once and reuse them across your app.*


# Writing Reactive code

*Note: This example leverages the excellent* [***scoped\_model library***](https://pub.dartlang.org/packages/scoped_model)*, which usage inspired the reactive pattern for flutter-view!*

**Flutter leaves us with a lot of freedom in how we want to write reactive code. Flutter-view proposes a structure but does not impose it.**

This guide will show you how we recommend you build a simple reactive app with an [MVVM approach](https://en.wikipedia.org/wiki/Model–view–viewmodel) using the ReactiveWidget and flutter-view. In essence building a reactive app in flutter-view always works the same:

1. **handle events from your views on the view-model**
2. **have the view-model call your business model for actions**
3. **have those actions update your business model data**
4. **have your views use the** [**reactive**](/reference/tag-shortcuts#reactive) **tag to listen for any updates**

Our app will look like this:

![](/files/-LTnqUOOqAJR6gnfQCjv)

You can find the[ full app source code](https://github.com/flutter-view/examples/tree/master/todolist) with some extra features added such as deleting and persistence in [the examples](/get-started/examples#todolist).

*Note: this approach requires you add the* [***flutter\_view\_widgets***](https://pub.dev/packages/flutter_view_widgets) *dependency to your project's **pubspec.yaml** file. It is also recommended to use VS Code with the* [***flutter-view extensions***](/get-started/vs-code-support)*.*

## The basic structure

To write our MVVM Flutter app, we create a couple of elements:

* **the app model:** the top level app data class with application level actions
* **the business model**: through classes that the represent logical data in our app
* **the views**: layouts that present data
* **the view-models**: models classes that are coupled to the views, and represent the data the views will present, as well as handle events in the views, and communicate to the app

To make things clearer, we will write a simple todo app. For this app, we will need each of the above elements:

* **lib/main.dart**: the starting point of our app
* **lib/model/app-model.dart**: contains the AppModel class that models our app
* **lib/model/task.dart**: contains the Task class that models a single task
* **lib/pages/taskspage/taskspage.dart**: the view of the taskspage, that shows all our tasks
* **lib/pages/taskspage/taskspage-model.dart**: the view-model of our taskspage

## Creating the business model

To create any model class, we extend the [**Model**](https://pub.dartlang.org/documentation/scoped_model/latest/scoped_model/Model-class.html) class from the [scoped model library](https://pub.dartlang.org/packages/scoped_model).

Our task has a name and can be done:

{% code title="lib/model/task.dart" %}

```dart
import 'package:meta/meta.dart';
import 'package:flutter_view_widgets/flutter_view_widgets.dart';

class Task extends Model {

  Task({@required this.name, this.done = false});

  String name;
  bool done;
}
```

{% endcode %}

Our application has a model that contains the list of tasks we want to keep:

{% code title="lib/model/appmodel.dart" %}

```dart
import 'package:flutter_view_widgets/flutter_view_widgets.dart';
import 'package:todolist/model/task.dart';

class AppModel extends Model {
  AppModel() {
    this.tasks = [];
  }

  List<Task> tasks;
}
```

{% endcode %}

Both **Task** and **AppModel** extend [**Model**](https://pub.dartlang.org/documentation/scoped_model/latest/scoped_model/Model-class.html). This allows them to be listened to for updates.&#x20;

In any reactive app you want to be able to inform views to react to the data changing. The views can listen to the models by calling [**model.addListener()**](https://pub.dartlang.org/documentation/scoped_model/latest/scoped_model/Model/addListener.html). You can then inform that data in a model has changed by calling [**model.notifyListeners()**](https://pub.dartlang.org/documentation/scoped_model/latest/scoped_model/Model/notifyListeners.html).

## Creating a view and view-model

To present the app, we need two basic things:

* the view model, a class that represents what we want to show on the page and handles any events and has presentation code
* the view, which contains code that lays out the widgets that paint what we see

Our view model starts out simple, for now it only needs a reference to the app, so it can show the tasks we have:

{% code title="lib/pages/taskspage/taskspage-model.dart" %}

```dart
import 'package:meta/meta.dart';
import 'package:flutter_view_widgets/flutter_view_widgets.dart';
import 'package:todolist/model/app-model.dart';

class TasksPageModel extends Model {
  TasksPageModel({@required this.app});

  final AppModel app;
}
```

{% endcode %}

Our view is a page scaffold with a list of tasks and a floating add button on the bottom right. In flutter-view, we can easily construct it using Pug:

{% tabs %}
{% tab title="lib/pages/taskspage/taskspage.pug" %}

```pug
import(package='flutter_view_widgets/flutter_view_widgets.dart')
import(package='todolist/model/app-model.dart')
import(package='todolist/model/task.dart')
import(file='taskspage-model.dart')

tasks-page(flutter-view :model[TasksPageModel])
	builder
		scaffold
			app-bar(as='appBar')
				#title(as='title') Tasks
				
			#body(as='body')
				center Here be tasks!

			floating-action-button(as='floatingActionButton')
				icon(:value='Icons.add')
```

{% endtab %}

{% tab title="lib/pages/taskspage/taskspage.dart" %}

```dart
// note: __flatten, ignores and package links removed for clarity
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter_view_tools/flutter_view_tools.dart';
import 'package:todolist/model/app-model.dart';
import 'package:todolist/model/task.dart';
import 'taskspage-model.dart';

Builder TasksPage({ @required TasksPageModel model }) {
  return Builder(
    builder: (context) {
      return Scaffold(
        appBar: AppBar(
          title: 
          //-- TITLE ----------------------------------------------------------
          Container(
            child: Text( 
              'Tasks',
            ),
          ),
        ),
        body: 
        //-- BODY ----------------------------------------------------------
        Container(
          child: Center(
            child: Text( 
              'Here be tasks!',
            ),
          ),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () { model.onAddButtonPressed(context); },
          child: Icon(
            Icons.add,
          ),
        ),
      );
    },
  );
}
```

{% endtab %}
{% endtabs %}

*Note: be sure to be running flutter-view -w lib in your project directory on a Terminal.*

Saving taskspage.pug will trigger flutter-view to create taskspage.dart next to it.

In lines **1-4** we [**import**](/guide/creating-a-new-view#adding-imports) all the elements we use in our view: the flutter\_view\_tools library and all our models.

Line **6** tells flutter-view to create a new function that takes a TasksPageModel as a parameter, and returns our widgets.

At line **7** we start with a builder. This is a convenient way to get access to the **context** variable. We will need this later.

Line **8** creates the Scaffold of our page. It has three parts: an AppBar at line **9-10**, a body with a placeholder text at line **12-13** and a FloatingActionButton at like **15-16**. For now, we are not yet showing the tasks.

## Wiring up the app

To use the **AppModel**, **Task**, **TasksPage** and **TasksPageModel** we just created, we need to start the app from **main.dart.**

The top-level widget we create in **main.dart** should do the following:

* create our **AppModel** and keep it in its state
* start as home with our **TasksPage** and pass a **TasksPageModel**

{% code title="main.dart" %}

```dart
import 'package:flutter/material.dart';
import 'package:todolist/model/app-model.dart';
import 'package:todolist/pages/taskspage/taskspage-model.dart';
import 'package:todolist/pages/taskspage/taskspage.dart';


void main() {
  runApp(TodoListApp());
}

class TodoListApp extends StatefulWidget {
  @override
  createState() => _TodoListAppState();
}

class _TodoListAppState extends State<TodoListApp> {
  /// The app contains a list of tasks and app-level functions
  AppModel app;

  @override
  void initState() {
    super.initState();
    app = AppModel();
  }

  @override
  build(context) => MaterialApp(
        title: 'Todo List',
        // we pass a new task page model into the page, with a reference to our app
        home: TasksPage(model: TasksPageModel(app: app)),
      );
}
```

{% endcode %}

At line **15** we create the state for our **TodoListApp.** It keeps the **AppModel** at line **17**. In the **initState()** method, we initialize our **app**.

We create the **MaterialApp** at line **26**. At line **29** we call **TasksPage**, and we pass as the **model** parameter the **TasksPageModel** as our view-model. The view-model in turn takes the **app** as a parameter.

Now that we have wired up all the basic parts, we can run our app:

![](/files/-LTnxGoosBJj0RtoNuIO)

## Showing data from the model

Now that the basic framework is in place, **we can use flutter-view to present model data it in the view**.

In the case of our app, we want to show the tasks from the **AppModel** in our **tasks-page**. When there are no tasks, we want to show a message that encourages someone to create the first task. When there are already tasks, we want to show the list.

First lets set some example starter tasks. In **AppModel**, add some starter tasks:

{% code title="app-model.dart" %}

```dart
// this.tasks = [];

this.tasks = [
  Task(name: 'Do the dishes', done: true),
  Task(name: 'Enjoy the day', done: false),
];

```

{% endcode %}

To actually show the tasks on the **tasks-page**, we can iterate through them with the flutter-view [**for property**](/guide/flow-control#for)**:**

{% code title="task-page.pug" %}

```pug
// #body(as='body')
//    center Here be tasks!

#body(as='body')
    list-view
        .task(for='task in model.app.tasks') ${task.name}
```

{% endcode %}

Now after hot reloading you should see the two tasks, as two lines of text.&#x20;

In line 5, we are creating an array of .task Containers, one for each element in **TaskPageModel.app.tasks.** In each container we put a text with the task name.

To clean up the presentation a bit, we can create a view that creates a single task, and repeat that instread. Add the following flutter-view code in **tasks-page.pug**:

{% code title="tasks-page.pug" %}

```pug
task-entry(flutter-view :task[Task] :model[TasksPageModel])
   card
      row
         .title ${task.name}
         checkbox(:^value='task.done')
```

{% endcode %}

This renders a single task entry.&#x20;

*Note the **value** property in the checkbox tag. It needs to be escaped because value is a reserved flutter-view keyword, used to pass an unnamed parameter.*

Now we can use it in the body:

{% code title="tasks-page.pug" %}

```pug
#body(as='body')
    list-view
        task-entry(for='task in model.app.tasks' :task='task' :model='model')
```

{% endcode %}

In line 3, we are again using for to repeat the tag for each task. A **task-entry** takes two parameters: the task and the model, so we pass both.

Finally, let's add some styling. Create a tasks-page.sass next to tasks-page.pug, and put in the following styling:

{% code title="tasks-page.sass" %}

```sass
task-entry
    card
        row
	    main-axis-alignment: space-between
	    .title
                margin-left: 20
                dafont-size: 20
```

{% endcode %}

Please compare this sass styling with the pug task-entry we added. The Row in task-entry gets assigned a space between main-axis-alignment, which pushes the text to the left and the checkbox to the right. Besides that we set a font size and margin to the **.title** Container.

See the generated task-page.dart to see what actually is being generated in Dart, by taking the Pug  and applying the styles with shortcuts. The result looks like this:

![](/files/-LU0tpTu-tt9v_4C_RUU)

## Making the view reactive

**To make a view react to changes in your model, use the** [**reactive tag**](/reference/tag-shortcuts#reactive)**.**

Now let us create a new task entry with the text "new task" whenever the user presses the + button. This requires the following steps:

1. listen to the event of the user pressing the button
2. handle the event in the view-model, asking the AppModel for a new task
3. have the AppModel create the new task
4. make the page-view react to changes to the AppModel.tasks

### Listening to the event of the user pressing the button

The + button is defined in tasks-page.pug. Change the code for the floating-action-button like this:

{% code title="tasks-page.pug" %}

```pug
floating-action-button(
    as='floatingActionButton'
    @on-pressed='model.onAddButtonPressed(context)')
    icon(:value='Icons.add')
```

{% endcode %}

The **@on-pressed** event handler is new. It calls **TasksPageModel.onAddButtonPressed()** with the current BuildContext. We need to create this method on **TasksPageModel.**

### **Handle the event in the view-model**

We want the view-model to ask the app to create a new task. Add the following code to **TasksPageModel** in tasks-page-model.dart:

{% code title="tasks-page-model.dart" %}

```dart
onAddButtonPressed(BuildContext context) {
    this.app.addTask(title: "new task");
}
```

{% endcode %}

### Have the AppModel create the new task

Now to create the new task in the AppModel, we need to create a task and add it to the list of tasks. Add the following code to **AppModel** in app-model.dart:

{% code title="app-model.dart" %}

```dart
addTask({String title}) {
  final task = Task(name: title);
  this.tasks.add(task);
  this.notifyListeners();
}
```

{% endcode %}

In line **2** we create the new task. We then add it. Finally and importantly, we need to call **notifyListeners()** on the AppModel. This will inform the interface to respond to the new task being added.

### Make the page-view react to changes to the AppModel.tasks

To make page-view react to changes of the **AppModel**, we need to watch the **AppModel** using the **reactive tag**. Since we pass the **AppModel** to the **TasksPageModel**, we can use model.app to get a reference to the **AppModel.** Update the tasks-page body again:

{% code title="tasks-page.pug" %}

```pug
// #body(as='body')

reactive(as='body' watch='model.app')
    list-view
        task-entry(for='task in model.app.tasks' :task='task' :model='model')
```

{% endcode %}

The only real replacement is that we changed a simple #body container into a reactive tag, that watches the app for changes. When the **notifyListeners()** call is made on the **AppModel**, everything below the reactive tag is reevaluated. Thus when we add a new task, it should now show in the view:

![](/files/-LU121Gh7BZxL4vMsGMJ)

## Using computed properties

Often you may need to calculate things for your presentation that are not possible with just simple layout presentation logic. Instead **you use the view-model to compute values for your view**.

For example, let's have the tasks that are completed have their title text decorated with strike-through. And as an exercise, let's have the text-decoration computed on the view-model instead of in the view. Update the task-entry in tasks-page.pug:

{% code title="tasks-page.pug" %}

```pug
task-entry(flutter-view :task[Task] :model[TasksPageModel])
    card
        row
            .title(:text-decoration='model.taskTextDecoration(task)')
                | ${task.name}
            checkbox(:^value='task.done')
```

{% endcode %}

At line 4 we have added a computed [**text-decoration**](/reference/css-properties#box-shadow-13) property. It starts with `:` so it will use the result of the expression we pass. This expression is **model.taskTextDecoration(task)**. We want this expression to return [**TextDecoration.lineThrough**](https://docs.flutter.io/flutter/dart-ui/TextDecoration/lineThrough-constant.html) if our passed current task is done. Let's add this method to the **TasksPageModel**:

{% code title="lib/pages/taskspage/taskspage-model.dart" %}

```dart
import 'package:meta/meta.dart';
import 'package:flutter_view_widgets/flutter_view_widgets.dart';
import 'package:todolist/model/app-model.dart';

class TasksPageModel extends Model {
  TasksPageModel({@required this.app});

  final AppModel app;
  
  taskTextDecoration(Task task) {
    return task.done ? TextDecoration.lineThrough : TextDecoration.none;
  }
}
```

{% endcode %}

Now completed tasks look more completed:

![done means done!](/files/-LU60Kzdxdc8fWfT72s3)

## Monitoring the state lifecycle

You may need to ***initialize*** some things in your **view-model** when the state of your layout starts, and ***free*** those resources when the state is disposed of. In that case, **use a** [**lifecycle**](/reference/tag-shortcuts#lifecycle) **widget**. It is part of the flutter-view-tools library.&#x20;

For example, let's say your **view** has a [**ListView**](https://docs.flutter.io/flutter/widgets/ListView-class.html) widget with a long list and you want to be able to load more items when you scroll near the bottom.

This requires we create a [**ScrollController**](https://docs.flutter.io/flutter/widgets/ScrollController-class.html) in the **view-model** and pass it to the [**ListView**](https://docs.flutter.io/flutter/widgets/ListView-class.html) in the **view**. We can then listen to the [**ScrollController**](https://docs.flutter.io/flutter/widgets/ScrollController-class.html) and react when the scrollposition is very low. Finally, when the **view** is disposed of, we also want our listener to be removed.

In the todo app we can do this as follows in the **view**:&#x20;

{% code title="tasks-page.pug" %}

```pug
#body(as='body')
    lifecycle(:on-init='model.init' :on-dispose='model.dispose')
        list-view(:controller='model.scrollController')
            task-entry(for='task in model.app.tasks' :task='task' :model='model')
```

{% endcode %}

At line **2** we add the [**lifecycle**](/reference/tag-shortcuts#lifecycle) widget with handlers for the init and dispose events, and pass them along to the **view-model**.&#x20;

At line **3** we pass the scrollController of the view-model to the list, so we can monitor the scrolling position.

The **view-model** needs to store the scrollController, initialize it and dispose of it:

{% code title="lib/pages/taskspage/taskspage-model.dart" %}

```dart
import 'package:meta/meta.dart';
import 'package:flutter/widgets.dart'
import 'package:flutter_view_widgets/flutter_view_widgets.dart';
import 'package:todolist/model/app-model.dart';

class TasksPageModel extends Model {
  TasksPageModel({@required this.app})
    : scrollController = ScrollController(initialScrollOffset: 0.0, keepScrollOffset: true);

  final AppModel app;
  final flutter.ScrollController scrollController;

  init() {
    this.scrollController.addListener(this.onScroll)
  }
  
  dispose() {
    this.scrollController.removeListener(this.onScroll)
  }
  
  onScroll() {
    if (this.scrollController.position.extentAfter < 500) {
      // if not already loading, load more entries here!
    }
  }
      
  taskTextDecoration(Task task) {
    return task.done ? TextDecoration.lineThrough : TextDecoration.none;
  }
}
```

{% endcode %}

At line 8 the **scrollController** is set up.

At lines **13** and **17** we add the **init** and **dispose** methods that are called by the lifecycle widget. These will start and stop listening to our scrollController.

Finally at line **21** we have an **onScroll** method that actually checks the scroll position and loads more entries.

## See the full example

This covers the basics of how to structure a reactive app with flutter-view, ScopedModel and the flutter-view-tools.

Of course our todo app is still incomplete, however you now should be able to understand the full implementation. See [the full example](/get-started/examples#todolist) with [source code](https://github.com/flutter-view/examples/tree/master/todolist) for a full implementation of this todo app. Notable additions there are:

* an add-task-dialog view that lets you enter a new task
* being able to check tasks as done
* swipe to delete tasks
* automatic saving and loading


# Styling per platform

When you write your Flutter app you probably want to target both iOS and Android. Flutter-view styling can make this easier for you, using the standard tools from CSS, Pug and Sass.

## The platform widgets library

First tip is, use the [**platform\_widgets library**](https://pub.dartlang.org/packages/flutter_platform_widgets), and add it as an [default import](/guide/configuring-flutter-view#imports) in flutter-view\.json:

{% code title="flutter-view\.json" %}

```javascript
{
	"imports": [
		"package:flutter_view_widgets/flutter_view_widgets.dart",
		"package:flutter_platform_widgets/flutter_platform_widgets.dart"
	]
}
```

{% endcode %}

Put `flutter-view.json` in the root of your Flutter project.

This will allow you to use widgets that adapt to the platform they are used on, and also provides you with the short [**isCupertino**](https://pub.dartlang.org/documentation/flutter_platform_widgets/latest/flutter_platform_widgets/isCupertino.html) and [**isMaterial**](https://pub.dartlang.org/documentation/flutter_platform_widgets/latest/flutter_platform_widgets/isMaterial.html) properties, that you can use throughout your layouts.

## Layout per platform

A common pattern is a [**slot**](/guide/flow-control#slot) with two implementations with two [**if**](/guide/flow-control#if) statements below it, one per platform:

{% tabs %}
{% tab title="pug" %}

```pug
.foo
    slot
        .ios(if='isCupertino')
            ...iOS layout here...
        .android(if='isMaterial')
            ...Android layout here...
```

{% endtab %}

{% tab title="sass" %}

```sass
.foo
    .ios
        // ios layout styling here
    .android
        // android layout styling here
```

{% endtab %}
{% endtabs %}

The above will render different layout depending on the phone OS you run it on. Since we are adding a different class, we can also add different styling through CSS.

## Same layout but different styling per platform

A very common situation is that we have the same basic layout, but want to use different CSS styling per layout. We could do the same as above:

```sass
.foo
    slot
        .ios(if='isCupertino')
            .some
                .layout
                    .here
        .android(if='isMaterial')
            .some
                .layout
                    .here
```

This will work, we can apply different styling for .bar.ios and .bar.android. However we are repeating ourselves in the layout. This can be quite redundant.

Instead, we can let Pug mixins help us. We can make a default.pug in our project that multiple view pugs can import. Then in this pug we can write a mixin:

{% code title="default.pug" %}

```pug
mixin platform-slot
    slot
        .ios-slot(if='isCupertino')
            .ios
                block
        .android-slot(if='isMaterial')
            .android
                block
```

{% endcode %}

We can then import this tool into our view and use it like this:

{% tabs %}
{% tab title="pug" %}

```pug
include /screens/default.pug

.foo
    platform-slot
        .some
            .layout
                .here
```

{% endtab %}

{% tab title="generated pug" %}

```pug
include /screens/default.pug

.foo
    slot
        .ios-slot(if='isCupertino')
            .ios
                .bar
                    .some
                        .layout
                            .here
        .android-slot(if='isMaterial')
            .android
                .bar
                    .some
                        .layout
                            .here 
```

{% endtab %}

{% tab title="css" %}

```
.foo
    .ios
        .some
            // ios layout styling here
    .android
        .some
            // android layout styling here
```

{% endtab %}
{% endtabs %}

Now we have no repetition in our layout!&#x20;

However, there is a downside: the generated pug will not know what source code line it came to, and as a result, you will not get the [source reference comments in the generated Dart](/guide/configuring-flutter-view#showpuglinenumbers). This means that in VSCode, the [flutter-view extension](/get-started/vs-code-support#linking-between-pug-and-generated-dart) hotlinking will not work for these lines.

*Note: kudos for Floris van der Grinten for this nifty solution*


# Special pug tags

A list of special tags you can use in your pug code that generate code in your Dart code.

## slot

A slot is a placeholder for a value. It will always take the value of the first valid child.

It is explained in more detailed in the [**flow control section**](/guide/flow-control).

## function

Creates a function, and uses the body as what is returned. This allows you to pass functions as parameters.

#### Parameters

* **params**: `@required String` a list of comma separated parameters your function expects

Example, to pass a builder function to a [**LayoutBuilder**](https://docs.flutter.io/flutter/widgets/LayoutBuilder-class.html):

{% tabs %}
{% tab title="Pug" %}

```pug
layout-builder
    function(as='builder' params='context, constraints')
        container Layout constraints: $constraints
```

{% endtab %}

{% tab title="generated Dart" %}

```dart
LayoutBuilder(
    builder: (context, constraints) {
        return Container(
            child: Text(
                'Layout constraints: $constraints'
            ),
        );
    }
)
```

{% endtab %}
{% endtabs %}

## builder

Wraps its child in a builder function that exposes the current [**BuildContext**](https://docs.flutter.io/flutter/widgets/BuildContext-class.html).

Quite frequently you may need the current build context in your views:

* passing it as a parameter into event handlers on your models
* for Theme.of(context) and such common constructions

At any time you need the current context, you can add a builder shortcut. It will write a Builder widget with as its child a function that passes the current context, which you can then use in the child widgets.

#### Parameters

No parameters.

Example:

{% tabs %}
{% tab title="Pug" %}

```pug
example(flutter-view)
	builder
		.welcome(color="theme(primary-color)") Hello!
```

{% endtab %}

{% tab title="generated Dart" %}

```dart
Example() {
  return Builder(
    builder: (context) {
      return DefaultTextStyle.merge( 
        child: 
        Container(
          child: Text( 
            'Hello!',
          ),
        ),
        style: TextStyle( 
          color: Theme.of(context).primaryColor,
        ),
      );
    },
  );
}
```

{% endtab %}
{% endtabs %}

In the above example, if you leave out the builder, you will get an error because theme requires a context. See the generated Dart how it is used.

## lifecycle

*Note: Requires the* [*flutter-view-widgets*](https://pub.dev/packages/flutter_view_widgets) *Dart library.*

Widget that lets you listen to the lifecycle of the `BuildContext` it is part of.

Useful in combination with `Model` and `ReactiveModel`, since your model can be informed when the `BuildContext` is being initialized, built, rendered and disposed of.

#### Parameters

* **onInit**: `Function` Called when [**initState**](https://docs.flutter.io/flutter/widgets/State/initState.html) is called on the widget state
* **onBuild**: `Function(BuildContext)` Called when [**build**](https://docs.flutter.io/flutter/widgets/State/build.html) is called on the widget state
* **onRender**: `Function` Called when render is called on the widget
* **onDispose**: `Function` Called when [**dispose**](https://docs.flutter.io/flutter/widgets/State/dispose.html) is called on the widget state

Example:

{% tabs %}
{% tab title="Pug" %}

```pug
example(flutter-view :model[MyModel])
	lifecycle(:on-dispose='model.onDisposed')
		| ${model.message}!
```

{% endtab %}

{% tab title="MyModel.dart" %}

```dart
class MyModel extends Model {
    
    String message = 'Hello world';
    
    onDisposed() {
        // we can do some cleanup here
    }
    
}
```

{% endtab %}

{% tab title="generated Dart" %}

```dart
Lifecycle Example({ @required model }) {
  return Lifecycle( // project://lib/pages/homepage/homepage.pug#21,2
    onDispose: model.onDisposed,
    child: Text( 
      '${model.message}',
    ),
  );
}
```

{% endtab %}
{% endtabs %}

For more information, see [monitoring the state lifecycle](/guide/writing-reactive-code#monitoring-the-state-lifecycle).&#x20;

## reactive

*Note: Requires the* [*flutter-view-widgets*](https://pub.dev/packages/flutter_view_widgets) *Dart library.*

Re-renders its children if the Listenable it watches updates.

This widget was made to work well with the [ScopedModel library](https://pub.dartlang.org/packages/scoped_model). However when using flutter-view, you no longer need to use the **ScopedModel** and **ScopedModelDescendant** widgets. Instead, you pass a model into a flutter-view, and use the reactive tag to watch for changes.

#### Parameters

* **watch**: `@required Listenable` Something to watch for updates. Usually a [**Model**](https://pub.dartlang.org/documentation/scoped_model/latest/scoped_model/Model-class.html).
* **child**: `@required Object` the rest of the widgets that get rerendered if the watched model updates

#### Implementation

The shortcut tag processor writes a [**ReactiveWidget**](https://pub.dartlang.org/documentation/flutter_view_tools/latest/flutter_view_tools/ReactiveWidget-class.html), and an associated builder function which gets called to build the widget layout.

{% tabs %}
{% tab title="Pug" %}

```pug
user-entry(flutter-view :user)
	reactive(watch='user')
		.name ${user.name}
		.age ${user.age}
```

{% endtab %}

{% tab title="generated Dart" %}

```dart
UserEntry({ @required user }) {
  return ReactiveWidget(
    watch: user as Listenable,
    builder: (context, $) {
      return Column( 
        children: [
          Container(
            child: Text( 
              '${user.name}',
            ),
          ),
          Container(
            child: Text( 
              '${user.age}',
            ),
          )
        ]),
      );
    },
  );
}

```

{% endtab %}
{% endtabs %}

In the above example, a user model is passed into the view. If a user is an instance of a Model, and user.notifyListeners() gets called, part below the reactive tag (the .name and .user containers) will automatically be re-rendered.

For more information and a more elaborate example, see [Writing Reactive code](/guide/writing-reactive-code).


# CSS style properties

A list of all the supported CSS style like shortcuts you can use as properties in your pug tags. These will then transform themselves into the appropriate Dart code.

## alignment

Describes where the content of a child should be positioned. Eg: text inside of a container.

Maps to Flutter [**Alignment**](https://docs.flutter.io/flutter/painting/Alignment-class.html) values in camelcase.

Valid values:

* **bottom-center:** The center point along the bottom edge
* **bottom-left:** The bottom left corner
* **bottom-right:** The bottom right corner
* **center:** The center point, both horizontally and vertically
* **center-left:** The center point along the left edge
* **center-right:** The center point along the right edge
* **top-center:** The center point along the top edge
* **top-left:** The top left corner
* **top-right:** The top right corner

Example:

{% tabs %}
{% tab title="Pug" %}

```pug
container(width=500 height=400)
    .greeting(alignment='center-right')
        | Hello, I am positioned at the right!

```

{% endtab %}

{% tab title="Dart" %}

```dart
Container(
  child: 
  Container(
    child: Text( 
      'Hello, I am positioned at the right!',
    ),
    alignment: Alignment.centerRight,
  ),
  width: 500,
  height: 400,
)
```

{% endtab %}
{% endtabs %}

## fit

Describes how a box should be inscribed into another box. Used for the [**FittedBox**](https://api.flutter.dev/flutter/widgets/FittedBox-class.html) Flutter container. Use the [background-size](/reference/css-properties#box-shadow-4) style property instead if you want to apply a sizing to a [background-image](/reference/css-properties#box-shadow-1).

Maps to Flutter [**BoxFit**](https://docs.flutter.io/flutter/painting/BoxFit-class.html) values in camelcase.

Valid values:

* **contain:** As large as possible while still containing the source entirely within the target box
* **cover:** As small as possible while still covering the entire target box.
* **fill:** Fill the target box by distorting the source's aspect ratio.
* **fill-height:** Make sure the full height of the source is shown, regardless of whether this means the source overflows the target box horizontally.
* **fill-width:** Make sure the full width of the source is shown, regardless of whether this means the source overflows the target box vertically.
* **none:** Align the source within the target box (by default, centering) and discard any portions of the source that lie outside the box. The source image is not resized.
* **scale-down:** Align the source within the target box (by default, centering) and, if necessary, scale the source down to ensure that the source fits within the box. This is the same as `contain` if that would shrink the image, otherwise it is the same as `none`.

See the [Flutter BoxFit documentation](https://docs.flutter.io/flutter/painting/BoxFit-class.html) for more information on these options.

Example:

{% tabs %}
{% tab title="Pug" %}

```pug
.cover-image(
    background-image="asset('images/background.jpg')"
    fit='cover')

```

{% endtab %}

{% tab title="Dart" %}

```dart
Container(
  decoration: BoxDecoration( 
    image: DecorationImage( 
      image: AssetImage(
        'images/background.jpg',
      ),
      fit: BoxFit.cover,
    ),
)
```

{% endtab %}
{% endtabs %}

## shape

Describes how the container should be shaped.

Maps to Flutter [**BoxShape**](https://docs.flutter.io/flutter/painting/BoxShape-class.html) values in camelcase. Creates a Flutter [**BoxDecoration**](https://docs.flutter.io/flutter/painting/BoxDecoration-class.html) with the [shape](https://docs.flutter.io/flutter/painting/BoxDecoration/shape.html) property set to to the value you pass.

Valid values:

* **circle:** A circle centered in the middle of the box into which the [Border](https://docs.flutter.io/flutter/painting/painting/Border-class.html) or [BoxDecoration](https://docs.flutter.io/flutter/painting/painting/BoxDecoration-class.html) is painted. The diameter of the circle is the shortest dimension of the box, either the width or the height, such that the circle touches the edges of the box.
* **rectangle:** An axis-aligned, 2D rectangle. May have rounded corners (described by a [BorderRadius](https://docs.flutter.io/flutter/painting/painting/BorderRadius-class.html)). The edges of the rectangle will match the edges of the box into which the [Border](https://docs.flutter.io/flutter/painting/painting/Border-class.html) or [BoxDecoration](https://docs.flutter.io/flutter/painting/painting/BoxDecoration-class.html) is painted.

Example:

{% tabs %}
{% tab title="Pug" %}

```pug
.cover-image(
    background-image="asset('images/background.jpg')"
    shape='circle')

```

{% endtab %}

{% tab title="Dart" %}

```dart
Container(
  decoration: BoxDecoration( 
    image: DecorationImage( 
      image: ExactAssetImage( 
        'images/background.jpg',
      ),
    ),
    shape: BoxShape.circle,
  ),
)
```

{% endtab %}
{% endtabs %}

## padding

Adds [padding](https://docs.flutter.io/flutter/widgets/Container/padding.html) to [containers](https://docs.flutter.io/flutter/widgets/Container-class.html).

Creates a Flutter padding property using[ **EdgeInsets.only()**](https://docs.flutter.io/flutter/painting/EdgeInsets/EdgeInsets.only.html)**.**

There are several padding properties you can use:

* **padding-left:** padding on the left side only
* **padding-right:** padding on the right side only
* **padding-top:** padding on the top side only
* **padding-bottom:** padding on the bottom side only
* **padding:** padding for all sides

These properties take values according to the [CSS specification](https://developer.mozilla.org/en-US/docs/Web/CSS/padding), with these exceptions:

* only direct values (numbers) are accepted
* no support for percentages

Examples of valid values:

```sass
padding-left: 10 // EdgeInsets.only(left: 10)
padding-top: 50 // EdgeInsets.only(top: 50)
padding: 10 // EdgeInsets.only(top: 10, left: 10, bottom: 10, right: 10)
padding: 5.5 7 // EdgeInsets.only(top: 5.5, left: 7, bottom: 5.5, right: 7)
```

Example:

{% tabs %}
{% tab title="Pug" %}

```pug
.greeting(padding=10) Hello world!
```

{% endtab %}

{% tab title="Dart" %}

```dart
Container(
  child: Text( 
    'Hello world!',
  ),
  padding: EdgeInsets.only(top: 10, right: 10, bottom: 10, left: 10),
)
```

{% endtab %}
{% endtabs %}

## margin

Adds [margin](https://docs.flutter.io/flutter/material/Card/margin.html) to [containers](https://docs.flutter.io/flutter/widgets/Container-class.html).

Creates a Flutter margin property using[ **EdgeInsets.only()**](https://docs.flutter.io/flutter/painting/EdgeInsets/EdgeInsets.only.html)**.**

There are several margin properties you can use:

* **margin-left:** margin on the left side only
* **margin-right:** margin on the right side only
* **margin-top:** margin on the top side only
* **margin-bottom:** margin on the bottom side only
* **margin:** margin for all sides

These properties take values according to the [CSS specification](https://developer.mozilla.org/en-US/docs/Web/CSS/margin), with these exceptions:

* only direct values (numbers) are accepted
* no support for percentages

Examples of valid values:

```css
margin-left: 10 // EdgeInsets.only(left: 10)
margin-top: 50 // EdgeInsets.only(top: 50)
margin: 10 // EdgeInsets.only(top: 10, left: 10, bottom: 10, right: 10)
margin: 5.5 7 // EdgeInsets.only(top: 5.5, left: 7, bottom: 5.5, right: 7)
```

Example:

{% tabs %}
{% tab title="Pug" %}

```pug
.greeting(margin=10) Hello world!
```

{% endtab %}

{% tab title="Dart" %}

```dart
Container(
  child: Text( 
    'Hello world!',
  ),
  margin: EdgeInsets.only(top: 10, right: 10, bottom: 10, left: 10),
)
```

{% endtab %}
{% endtabs %}

## border-radius

Decorates a container with rounded borders.

Creates a Flutter [**BoxDecoration**](https://docs.flutter.io/flutter/painting/BoxDecoration-class.html) with [borderRadius](https://docs.flutter.io/flutter/painting/BoxDecoration/borderRadius.html) set using [**BorderRadius.only()**](https://docs.flutter.io/flutter/painting/BorderRadius/BorderRadius.only.html). The values passed to BorderRadius.only for each corner are values of [**Radius.circular()**](https://docs.flutter.io/flutter/dart-ui/Radius/Radius.circular.html).

The border-radius property takes values according to the [CSS specification](https://developer.mozilla.org/en-US/docs/Web/CSS/border-radius), with these exceptions:

* only direct values (numbers) are accepted
* no support for percentages

Examples of valid values:

```css
border-radius: 5 // BorderRadius.only(topLeft: Radius.circular(5), topRight: Radius.circular(5), bottomRight: Radius.circular(5), bottomLeft: Radius.circular(5))
border-radius: 2 5 2.5 7 // BorderRadius.only(topLeft: Radius.circular(2), topRight: Radius.circular(5), bottomRight: Radius.circular(2.5), bottomLeft: Radius.circular(7))
border-radius: 5 4 // BorderRadius.only(topLeft: Radius.circular(5), topRight: Radius.circular(4), bottomRight: Radius.circular(5), bottomLeft: Radius.circular(4))
```

Example:

{% tabs %}
{% tab title="Pug" %}

```pug
.greeting(border-radius=4 background-color='grey') Hello world!
```

{% endtab %}

{% tab title="Dart" %}

```dart
Container( // project://lib/pages/homepage/homepage.pug#8,5
  child: Text( 
    'Hello world!',
  ),
  decoration: BoxDecoration( 
    color: Colors.grey,
    borderRadius: BorderRadius.only(topLeft: Radius.circular(5), topRight: Radius.circular(5), bottomRight: Radius.circular(5), bottomLeft: Radius.circular(5)),
  ),
)
```

{% endtab %}
{% endtabs %}

## border

Adds [borders](https://docs.flutter.io/flutter/painting/Border-class.html) to [containers](https://docs.flutter.io/flutter/widgets/Container-class.html).

Creates a Flutter Border widget property using[ **EdgeInsets.only()**](https://docs.flutter.io/flutter/painting/EdgeInsets/EdgeInsets.only.html)**.**

Creates a Flutter [**BoxDecoration**](https://docs.flutter.io/flutter/painting/BoxDecoration-class.html) with [**border**](https://docs.flutter.io/flutter/painting/BoxDecoration/border.html) set using [**Border()**](https://docs.flutter.io/flutter/painting/Border-class.html). The values passed to Border() for each side are values of [**BorderSide**](https://docs.flutter.io/flutter/painting/BorderSide-class.html), with an optional width, style and color.

There are several border properties you can use:

* **border-left:** style of the left border
* **border-right:** style of the right border
* **border-top:** style of the top border
* **border-bottom:** style of the bottom border
* **border:** style for all border sides
* **border-style**: line style for all border sides
* **border-width**: width of all border sides
* **border-color**: color of all border sides

These properties take values according to the [CSS specification](https://developer.mozilla.org/en-US/docs/Web/CSS/border), with these exceptions:

* for styles, only solid and none are accepted
* width must be a number
* color must be a name *(this is a bug, will be fixed soon)*
* the **border** property only allows a single style for all, not a style per side

Examples of valid values:

```css
border-left: 1 solid red
border-width: 3.3
border: none
border: 5.5 blue
```

Example:

{% tabs %}
{% tab title="Pug" %}

```pug
.greeting(border-top='1.4 red' border-bottom='0.5 green') Hello world!
```

{% endtab %}

{% tab title="Dart" %}

```dart
Container(
  child: Text( 
    'Hello world!',
  ),
  decoration: BoxDecoration( 
    border: Border( 
      top: BorderSide( 
        width: 1.4,
        color: Colors.red,
      ),
      bottom: BorderSide( 
        width: 0.5,
        color: Colors.green,
      ),
    ),
  ),
)
```

{% endtab %}
{% endtabs %}

## box-shadow

Adds shadows to [containers](https://docs.flutter.io/flutter/widgets/Container-class.html).

Creates a Flutter [**BoxDecoration**](https://docs.flutter.io/flutter/painting/BoxDecoration-class.html) with the [boxShadow](https://docs.flutter.io/flutter/painting/BoxDecoration/boxShadow.html) property set using [**BoxShadow**](https://docs.flutter.io/flutter/painting/BoxShadow-class.html).

It suppors multiple passed box shadows, separated by a comma.

A single box shadow can have 2, 3 or 4 or 5 properties: offset-x, offset-y, and optionally blur-radius offset-radius and color.

These properties take values according to the [CSS specification](https://developer.mozilla.org/en-US/docs/Web/CSS/box-shadow), with these exceptions:

* values must be numbers
* colors not yet supported (coming soon)
* no support for the inset keyword

Examples of valid values:

```css
box-shadow: 2 3 // single shadow with offset-x: 3, offset-y: 3
box-shadow: 2 2 5 // single shadow with offset-x: 2, offset-y: 2 and blur: 5
box-shadow: 4 3 6 7 // single grey shadow with blur: 6 and offset-radius: 7
box-shadow: 2 3, 3 4 9 4 // two box shadows example
```

Example:

{% tabs %}
{% tab title="Pug" %}

```pug
.greeting(box-shadow='2 3 5 7, -5 -2') Hello world!
```

{% endtab %}

{% tab title="Dart" %}

```dart
Container(
  child: Text( 
    'Hello world!',
  ),
  decoration: BoxDecoration( 
    boxShadow: [
      BoxShadow( 
        offset: Offset(2.00, 3.00),
        blurRadius: 5.00,
        spreadRadius: 7.00,
      ),
      BoxShadow( 
        offset: Offset(-5.00, -2.00),
      )
    ],
  ),
)
```

{% endtab %}
{% endtabs %}

## background-image <a href="#box-shadow" id="box-shadow"></a>

Sets a background image to [containers](https://docs.flutter.io/flutter/widgets/Container-class.html).

Creates a Flutter [**BoxDecoration**](https://docs.flutter.io/flutter/painting/BoxDecoration-class.html) with the [image](https://docs.flutter.io/flutter/painting/BoxDecoration/image.html) property set using either [**NetworkImage**](https://docs.flutter.io/flutter/painting/NetworkImage-class.html) or [**ExactAssetImage**](https://docs.flutter.io/flutter/painting/ExactAssetImage-class.html).

The background-image property can have one of two values:

* **url("\<image-url>")** : creates a NetworkImage for the given url
* **asset("\<asset-name>")**: uses an ExactAssetImage for the given name

Examples of valid values:

```css
background-image: asset('images/background.jpg')
background-image: url('http://some/image/url.png')
```

Example:

{% tabs %}
{% tab title="Pug" %}

```pug
.cover-image(background-image="asset('images/background.jpg')")
```

{% endtab %}

{% tab title="Dart" %}

```dart
Container(
  decoration: BoxDecoration( 
    image: DecorationImage( 
      image: ExactAssetImage( 
        'images/background.jpg',
      ),
    ),
  ),
)
```

{% endtab %}
{% endtabs %}

## ​background-color <a href="#box-shadow" id="box-shadow"></a>

Sets a background color to [containers](https://docs.flutter.io/flutter/widgets/Container-class.html).

Creates a Flutter [**BoxDecoration**](https://docs.flutter.io/flutter/painting/BoxDecoration-class.html) with the [color](https://docs.flutter.io/flutter/painting/BoxDecoration/color.html) property set to the value you pass as a [**Color**](https://docs.flutter.io/flutter/dart-ui/Color-class.html).

See the [color property](/reference/css-properties#color-color) on valid values.

Example:

{% tabs %}
{% tab title="Pug" %}

```pug
.redbox(width=200 height=200 background-color="red")
```

{% endtab %}

{% tab title="Dart" %}

```dart
Container(
  decoration: BoxDecoration( 
    color: Colors.red,
  ),
  width: 200,
  height: 200,
)
```

{% endtab %}
{% endtabs %}

## background-repeat <a href="#box-shadow" id="box-shadow"></a>

Sets how background images of a [container](https://docs.flutter.io/flutter/widgets/Container-class.html) should be repeated. Usually used together with [**background-image**](/reference/css-properties#box-shadow-1).

Creates a Flutter [**BoxDecoration**](https://docs.flutter.io/flutter/painting/BoxDecoration-class.html) with the repeat property of the image set to the value you pass.&#x20;

Maps to Flutter [**ImageRepeat**](https://docs.flutter.io/flutter/painting/ImageRepeat-class.html) values in camelcase.

Valid values:

* **no-repeat:** Leave uncovered portions of the box transparent
* **repeat:** Repeat the image in both the x and y directions until the box is filled.
* **repeat-x:** Repeat the image in the x direction until the box is filled horizontally.
* **repeat-y:** Repeat the image in the y direction until the box is filled vertically.

Example:

{% tabs %}
{% tab title="Pug" %}

```pug
.cover-image(
    background-image="asset('images/background.jpg')" 
    background-repeat='no-repeat')
```

{% endtab %}

{% tab title="Dart" %}

```dart
Container( // project://lib/pages/homepage/homepage.pug#8,5
  decoration: BoxDecoration( 
    image: DecorationImage( 
      image: ExactAssetImage( 
        'images/background.jpg',
      ),
      repeat: ImageRepeat.noRepeat,
    ),
  ),
)
```

{% endtab %}
{% endtabs %}

## background-size <a href="#box-shadow" id="box-shadow"></a>

Sets how background images of a [container](https://docs.flutter.io/flutter/widgets/Container-class.html) should be fitted in the container. Usually used together with [**background-image**](/reference/css-properties#box-shadow-1).

It does so by setting the [fit](https://docs.flutter.io/flutter/painting/DecorationImage/fit.html) property of the [**ImageDecoration**](https://docs.flutter.io/flutter/painting/DecorationImage-class.html) that was created for the **background-image**.

See the [**fit property**](/reference/css-properties#fit) above for valid values and more information.

Example:

{% tabs %}
{% tab title="Pug" %}

```pug
.cover-image(
    background-image="asset('images/background.jpg')" 
    background-fit='cover')
```

{% endtab %}

{% tab title="Dart" %}

```dart
Container(
  decoration: BoxDecoration( 
    image: DecorationImage( 
      image: ExactAssetImage( 
        'images/background.jpg',
      ),
      fit: BoxFit.cover,
    ),
  ),
)
```

{% endtab %}
{% endtabs %}

## main-axis-alignment <a href="#box-shadow" id="box-shadow"></a>

Controls how a row or column aligns its children on the main axis. See the [Flutter layout documentation](https://flutter.io/docs/development/ui/layout#aligning-widgets) for more information.

Maps to Flutter [**MainAxisAlignment**](https://docs.flutter.io/flutter/rendering/MainAxisAlignment-class.html) enum values in camelcase.

Valid values:

* **start:** Place the children as close to the start of the main axis as possible
* **end:** Place the children as close to the end of the main axis as possible
* **center:** Place the children as close to the middle of the main axis as possible
* **space-around:** Place the free space evenly between the children as well as half of that space before and after the first and last child
* **space-between:** Place the free space evenly between the children
* **space-evenly:** Place the free space evenly between the children as well as before and after the first and last child

Example:

{% tabs %}
{% tab title="Pug" %}

```pug
row(main-axis-alignment="space-evenly")
    .entry We
    .entry Are
    .entry Spaced
    .entry Evenly
```

{% endtab %}

{% tab title="Dart" %}

```dart
Row(
  children: [
    Container(
      child: Text( 
        'We',
      ),
    ),
    Container(
      child: Text( 
        'Are',
      ),
    ),
    Container(
      child: Text( 
        'Spaced',
      ),
    ),
    Container(
      child: Text( 
        'Evenly',
      ),
    )
  ],
  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
)
```

{% endtab %}
{% endtabs %}

## cross-axis-alignment <a href="#box-shadow" id="box-shadow"></a>

Controls how a row or column aligns its children on the cross axis. See the [Flutter layout documentation](https://flutter.io/docs/development/ui/layout#aligning-widgets) for more information.

Maps to Flutter [**CrossAxisAlignment**](https://docs.flutter.io/flutter/rendering/CrossAxisAlignment-class.html) enum values in camelcase.

Valid values:

* **start:** Place the children with their start edge aligned with the start side of the cross axis
* **end:** Place the children as close to the end of the cross axis as possible
* **center:** Place the children so that their centers align with the middle of the cross axis
* **baseline:** Place the children along the cross axis such that their baselines match
* **stretch:** Require the children to fill the cross axis

Example:

{% tabs %}
{% tab title="Pug" %}

```pug
column(cross-axis-alignment="center")
    .entry We
    .entry Are
    .entry Centered
```

{% endtab %}

{% tab title="Dart" %}

```dart
Column(
  children: [
    Container(
      child: Text( 
        'We',
      ),
    ),
    Container(
      child: Text( 
        'Are',
      ),
    ),
    Container(
      child: Text( 
        'Centered',
      ),
    )
  ],
  crossAxisAlignment: CrossAxisAlignment.center,
),
```

{% endtab %}
{% endtabs %}

## main-axis-size <a href="#box-shadow" id="box-shadow"></a>

Controls how a row or column to deals with left-over free space in the main axis. See the [Flutter layout documentation](https://flutter.io/docs/development/ui/layout#aligning-widgets) for more information.

Maps to Flutter [**MainAxisSize**](https://docs.flutter.io/flutter/rendering/MainAxisSize-class.html) enum values in camelcase.

Valid values:

* **min:** Minimize the amount of free space along the main axis, subject to the incoming layout constraints
* **max:** Maximize the amount of free space along the main axis, subject to the incoming layout constraints

Example:

{% tabs %}
{% tab title="Pug" %}

```pug
column(main-axis-size="max")
    .entry Some entry, left over space is maximized
```

{% endtab %}

{% tab title="Dart" %}

```dart
Column(
  children: [

    //-- ENTRY ----------------------------------------------------------
    Container( // project://lib/pages/homepage/homepage.pug#14,6
      child: Text( 
        'Some entry, left over space is maximized',
      ),
    )
  ],
  mainAxisSize: MainAxisSize.max,
)
```

{% endtab %}
{% endtabs %}

## color, ...-color

Assigns a [**Color**](https://docs.flutter.io/flutter/dart-ui/Color-class.html) to a property. It works on any property either named color, or ending with -color.

When a color is set on a [**Container**](https://docs.flutter.io/flutter/widgets/Container-class.html), it will set the text color, much like you would set a color CSS property on a DIV in HTML. It does so by wrapping the container with [**DefaultTextStyle.merge**](https://docs.flutter.io/flutter/widgets/DefaultTextStyle/merge.html) and setting the text color in the [**TextStyle**](https://docs.flutter.io/flutter/painting/TextStyle-class.html) that is passed.

Valid values:

* Any expression that evalutes to a [**Color**](https://docs.flutter.io/flutter/dart-ui/Color-class.html). `:color='Colors.red'`
* A dash-cased color name from Colors. `color='deep-orange'`
* A dash-cased color name from Colors with a weight. `color='deep-orange[400]'`
* A hex color ala CSS. `color='#FF3499'`&#x20;
* A hex color ala CSS with preceding transparency. `color='#80FF3499'`

Examples:

{% tabs %}
{% tab title="Using Pug" %}

```pug
.red-text-container(color='red') This text is red
.red-container(:background-color='Colors.red')
.orange-container(background-color='deep-orange')
.green-container(background-color='green[300]')
.blue-container(background-color='#00F')
.blue-container2(background-color='#0000FF')
```

{% endtab %}

{% tab title="Using CSS" %}

```css
.red-text-container
    color: red
.red-container
    background-color: ':Colors.red'
.orange-container
    background-color: deep-orange
.green-container
    background-color: green[300]
.blue-container
    background-color: #00F
.blue-container2
    background-color: #0000FF
```

{% endtab %}

{% tab title="generated Dart" %}

```dart
Column( 
  children: [
    DefaultTextStyle.merge( 
      child: 
      //-- RED-TEXT-CONTAINER ----------------------------------------------------------
      Container(
        child: Text( 
          'This text is red',
        ),
      ),
      style: TextStyle( 
        color: Colors.red,
      ),
    ),

    //-- RED-CONTAINER ----------------------------------------------------------
    Container(
      decoration: BoxDecoration( 
        color: Colors.red,
      ),
    ),

    //-- ORANGE-CONTAINER ----------------------------------------------------------
    Container(
      decoration: BoxDecoration( 
        color: Colors.deepOrange,
      ),
    ),

    //-- GREEN-CONTAINER ----------------------------------------------------------
    Container(
      decoration: BoxDecoration( 
        color: Colors.green.shade300,
      ),
    ),

    //-- BLUE-CONTAINER ----------------------------------------------------------
    Container(
      decoration: BoxDecoration( 
        color: Color(0xFF0000FF),
      ),
    ),

    //-- BLUE-CONTAINER2 ----------------------------------------------------------
    Container(
      decoration: BoxDecoration( 
        color: Color(0xFF0000FF),
      ),
    )
  ],
)
```

{% endtab %}
{% endtabs %}

## font-size <a href="#box-shadow" id="box-shadow"></a>

Sets the font size of text in the container and all its children. Only works on Containers.

It does so by wrapping the container with [**DefaultTextStyle.merge**](https://docs.flutter.io/flutter/widgets/DefaultTextStyle/merge.html) and setting the font size in the [**TextStyle**](https://docs.flutter.io/flutter/painting/TextStyle-class.html) that is passed.&#x20;

Allowed values are ints, doubles and theme font sizes.

Example:

{% tabs %}
{% tab title="Pug" %}

```pug
.test(font-size=12.5) Welcome!
```

{% endtab %}

{% tab title="Dart" %}

```dart
DefaultTextStyle.merge( 
  child: Container(
    child: Text( 
      'Welcome!',
    ),
  ),
  style: TextStyle( 
    fontSize: 12.5,
  ),
)
```

{% endtab %}
{% endtabs %}

## font-weight <a href="#box-shadow" id="box-shadow"></a>

Sets the font weight of text in the container and all its children. Only works on Containers.

It does so by wrapping the container with [**DefaultTextStyle.merge**](https://docs.flutter.io/flutter/widgets/DefaultTextStyle/merge.html) and setting the font weight in the [**TextStyle**](https://docs.flutter.io/flutter/painting/TextStyle-class.html) that is passed.&#x20;

Maps to Flutter [**FontWeight**](https://docs.flutter.io/flutter/dart-ui/FontWeight-class.html) enum values in camelcase.&#x20;

Valid values:

* **normal:** The default font weight
* **bold:** A commonly used font weight that is heavier than normal
* **w100:** Thin, the least thick
* **w200:** Extra light
* **w300:** Light
* **w400:** Normal / regular / plain
* **w500:** Medium
* **w600:** Semi bold
* **w700:** Bold
* **w800:** Extra bold
* **w900:** Black, the most thick

*Note: Instead of passing w100, you may also pass 100, etc.*

Example:

{% tabs %}
{% tab title="Pug" %}

```pug
.test(font-weight='bold') Welcome!
```

{% endtab %}

{% tab title="Dart" %}

```dart
DefaultTextStyle.merge( 
  child: 
  Container(
    child: Text( 
      'Welcome!',
    ),
  ),
  style: TextStyle( 
    fontWeight: FontWeight.bold,
  ),
)
```

{% endtab %}
{% endtabs %}

## font-family <a href="#box-shadow" id="box-shadow"></a>

Sets the font family of text in the container and all its children. Only works on Containers.

It does so by wrapping the container with [**DefaultTextStyle.merge**](https://docs.flutter.io/flutter/widgets/DefaultTextStyle/merge.html) and setting the font family in the [**TextStyle**](https://docs.flutter.io/flutter/painting/TextStyle-class.html) that is passed.&#x20;

Value must be a string.

Example:

{% tabs %}
{% tab title="Pug" %}

```pug
.test(font-size='Arial') Welcome!
```

{% endtab %}

{% tab title="Dart" %}

```dart
DefaultTextStyle.merge( 
  child: Container(
    child: Text( 
      'Welcome!',
    ),
  ),
  style: TextStyle( 
    fontFamily: 'Arial',
  ),
)
```

{% endtab %}
{% endtabs %}

## font-style <a href="#box-shadow" id="box-shadow"></a>

Sets the font style of text in the container and all its children. Only works on Containers.

It does so by wrapping the container with [**DefaultTextStyle.merge**](https://docs.flutter.io/flutter/widgets/DefaultTextStyle/merge.html) and setting the font style in the [**TextStyle**](https://docs.flutter.io/flutter/painting/TextStyle-class.html) that is passed.&#x20;

Maps to Flutter [**FontStyle**](https://docs.flutter.io/flutter/dart-ui/FontStyle-class.html) enum values in camelcase.&#x20;

Valid values:

* **normal:** The default font style
* **italic:** Use glyphs designed for slanting

Example:

{% tabs %}
{% tab title="Pug" %}

```pug
.test(font-style='italic') Welcome!
```

{% endtab %}

{% tab title="Dart" %}

```dart
DefaultTextStyle.merge( 
  child: 
  Container(
    child: Text( 
      'Welcome!',
    ),
  ),
  style: TextStyle( 
    fontStyle: FontStyle.italic,
  ),
)
```

{% endtab %}
{% endtabs %}

## letter-spacing <a href="#box-shadow" id="box-shadow"></a>

The amount of space (in logical pixels) to add between each letter. A negative value can be used to bring the letters closer. Only works on Containers.

It does so by wrapping the container with [**DefaultTextStyle.merge**](https://docs.flutter.io/flutter/widgets/DefaultTextStyle/merge.html) and setting the letter spacing in the [**TextStyle**](https://docs.flutter.io/flutter/painting/TextStyle-class.html) that is passed.&#x20;

Valid values are ints and doubles.

Example:

{% tabs %}
{% tab title="Pug" %}

```pug
.test(letter-spacing=3) This text gets spaced out
```

{% endtab %}

{% tab title="Dart" %}

```
DefaultTextStyle.merge( 
  child: 
  Container(
    child: Text( 
      'This text gets spaced out',
    ),
  ),
  style: TextStyle( 
    letterSpacing: 3,
  ),
)
```

{% endtab %}
{% endtabs %}

## line-height <a href="#box-shadow" id="box-shadow"></a>

Sets the line height text in the container and all its children. Only works on Containers.

It does so by wrapping the container with [**DefaultTextStyle.merge**](https://docs.flutter.io/flutter/widgets/DefaultTextStyle/merge.html) and setting the line height in the [**TextStyle**](https://docs.flutter.io/flutter/painting/TextStyle-class.html) that is passed.&#x20;

Valid values are ints and doubles.

Example:

{% tabs %}
{% tab title="Pug" %}

```pug
.test(line-height=20) Welcome!
```

{% endtab %}

{% tab title="Dart" %}

```dart
DefaultTextStyle.merge( 
  child: 
  Container(
    child: Text( 
      'Welcome!',
    ),
  ),
  style: TextStyle( 
    height: 20,
  ),
)
```

{% endtab %}
{% endtabs %}

## text-decoration <a href="#box-shadow" id="box-shadow"></a>

A linear decoration to draw near the text.

It does so by wrapping the container with [**DefaultTextStyle.merge**](https://docs.flutter.io/flutter/widgets/DefaultTextStyle/merge.html) and setting the textDecoration in the [**TextStyle**](https://docs.flutter.io/flutter/painting/TextStyle-class.html) that is passed.&#x20;

Maps to Flutter [**TextDecoration**](https://docs.flutter.io/flutter/dart-ui/TextDecoration-class.html) enum values in camelcase.&#x20;

Valid values:

* **none:** Do not draw a decoration
* **underline:** Draw a line underneath each line of text
* **overline:** Draw a line above each line of text
* **line-through:** Draw a line through each line of text

Example:

{% tabs %}
{% tab title="Pug" %}

```pug
.test(text-decoration='underline') Welcome!
```

{% endtab %}

{% tab title="Dart" %}

```dart
DefaultTextStyle.merge( 
  child: 
  Container(
    child: Text( 
      'Welcome!',
    ),
  ),
  style: TextStyle( 
    textDecoration: TextDecoration.underline,
  ),
)
```

{% endtab %}
{% endtabs %}

## text-decoration-color <a href="#box-shadow" id="box-shadow"></a>

The color of the text decoration you have set.

It does so by wrapping the container with [**DefaultTextStyle.merge**](https://docs.flutter.io/flutter/widgets/DefaultTextStyle/merge.html) and setting the decorationColor in the [**TextStyle**](https://docs.flutter.io/flutter/painting/TextStyle-class.html) that is passed.&#x20;

The value must be a valid [**color** property](/reference/css-properties#color-color) value.

Example:

{% tabs %}
{% tab title="Pug" %}

```pug
.test(
    text-decoration='underline'
    text-decoration-color='red') 
    | Hello world!
```

{% endtab %}

{% tab title="Dart" %}

```dart
DefaultTextStyle.merge( 
  child: Container(
    child: Text( 
      'Hello world!',
    ),
  ),
  style: TextStyle( 
    decoration: TextDecoration.underline,
    decorationColor: Colors.red,
  ),
)
```

{% endtab %}
{% endtabs %}

## text-decoration-style <a href="#box-shadow" id="box-shadow"></a>

The style in which to draw a text decoration.

It does so by wrapping the container with [**DefaultTextStyle.merge**](https://docs.flutter.io/flutter/widgets/DefaultTextStyle/merge.html) and setting the decorationStyle in the [**TextStyle**](https://docs.flutter.io/flutter/painting/TextStyle-class.html) that is passed.&#x20;

Maps to Flutter [**TextDecorationStyle**](https://docs.flutter.io/flutter/dart-ui/TextDecorationStyle-class.html) enum values in camelcase.&#x20;

Valid values:

* **solid:** Draw a solid line
* **double:** Draw two lines
* **dotted:** Draw a dotted line
* **dashed:** Draw a dashed line
* **wavy:** Draw a sinusoidal line

Example:

{% tabs %}
{% tab title="Pug" %}

```pug
.test(
	text-decoration='underline'
	text-decoration-style='wavy') 
	| Hello world!
```

{% endtab %}

{% tab title="Dart" %}

```dart
DefaultTextStyle.merge( 
  child: Container( // project://lib/pages/homepage/homepage.pug#8,5
    child: Text( 
      'Hello world!',
    ),
  ),
  style: TextStyle( 
    decoration: TextDecoration.underline,
    decorationStyle: TextDecorationStyle.wavy,
  ),
)
```

{% endtab %}
{% endtabs %}

## word-spacing <a href="#box-shadow" id="box-shadow"></a>

Sets the space between words in a text.

It does so by wrapping the container with [**DefaultTextStyle.merge**](https://docs.flutter.io/flutter/widgets/DefaultTextStyle/merge.html) and setting the wordSpacing in the [**TextStyle**](https://docs.flutter.io/flutter/painting/TextStyle-class.html) that is passed.&#x20;

Valid values are ints and doubles.

Example:

{% tabs %}
{% tab title="Pug" %}

```pug
.test(word-spacing=5.3) Welcome!
```

{% endtab %}

{% tab title="Dart" %}

```dart
DefaultTextStyle.merge( 
  child: 
  Container(
    child: Text( 
      'Welcome!',
    ),
  ),
  style: TextStyle( 
    wordSpacing: 5.3,
  ),
)
```

{% endtab %}
{% endtabs %}

## text-align <a href="#box-shadow" id="box-shadow"></a>

Whether and how to align text horizontally.

It does so by wrapping the container with [**DefaultTextStyle.merge**](https://docs.flutter.io/flutter/widgets/DefaultTextStyle/merge.html) and setting the textAlign in the [**TextStyle**](https://docs.flutter.io/flutter/painting/TextStyle-class.html) that is passed.&#x20;

Maps to Flutter [**TextAlign**](https://docs.flutter.io/flutter/dart-ui/TextAlign-class.html) enum values in camelcase.&#x20;

Valid values:

* **start:** Align the text on the leading edge of the container.
* **end:** Align the text on the trailing edge of the container.
* **left:** Align the text on the left edge of the container.
* **right:** Align the text on the right edge of the container.
* **center:** Align the text in the center of the container.
* **justify:** Stretch lines of text that end with a soft line break to fill the width of the container.

Example:

{% tabs %}
{% tab title="Pug" %}

```pug
.test(text-align='center') Welcome!
```

{% endtab %}

{% tab title="Dart" %}

```dart
DefaultTextStyle.merge( 
  child: 
  Container(
    child: Text( 
      'Welcome!',
    ),
  ),
  style: TextStyle( 
    textAlign: TextAlign.center,
  ),
)
```

{% endtab %}
{% endtabs %}

## text-overflow <a href="#box-shadow" id="box-shadow"></a>

A linear decoration to draw near the text.

It does so by wrapping the container with [**DefaultTextStyle.merge**](https://docs.flutter.io/flutter/widgets/DefaultTextStyle/merge.html) and setting the overflow in the [**TextStyle**](https://docs.flutter.io/flutter/painting/TextStyle-class.html) that is passed.&#x20;

Maps to Flutter [**TextOverflow**](https://docs.flutter.io/flutter/rendering/TextOverflow-class.html) enum values in camelcase.&#x20;

Valid values:

* **clip:** Clip the overflowing text to fix its container.
* **ellipsis:** Use an ellipsis to indicate that the text has overflowed.
* **fade:** Fade the overflowing text to transparent.

Example:

{% tabs %}
{% tab title="Pug" %}

```pug
.test(text-overflow='ellipsis' width=200) 
    | This will be cut off nicely with ellipsis
```

{% endtab %}

{% tab title="Dart" %}

```dart
DefaultTextStyle.merge( 
  child: Container(
    child: Text( 
      'This will be cut off nicely with ellipsis',
    ),
    width: 200,
  ),
  overflow: TextOverflow.ellipsis,
)
```

{% endtab %}
{% endtabs %}

## text-transform <a href="#box-shadow" id="box-shadow"></a>

Changes the case of the text. It follows the CSS standards.

Valid values:

* **uppercase:** changes the text to uppercase
* **lowercase:** changes the text to lowercase

Example:

{% tabs %}
{% tab title="Pug" %}

```pug
.test(text-transform='uppercase') 
    | This text will be shown in uppercase
```

{% endtab %}

{% tab title="Dart" %}

```dart
Container(
  child: Text( 
    'This text will be shown in uppercase'.toUpperCase(),
  ),
)
```

{% endtab %}
{% endtabs %}

## max-lines <a href="#box-shadow" id="box-shadow"></a>

Sets an optional maximum number of lines for the text to span, wrapping if necessary. If the text exceeds the given number of lines, it will be truncated according to [**overflow**](/reference/css-properties#box-shadow-18).

It does so by wrapping the container with [**DefaultTextStyle.merge**](https://docs.flutter.io/flutter/widgets/DefaultTextStyle/merge.html) and setting the maxLines in the [**TextStyle**](https://docs.flutter.io/flutter/painting/TextStyle-class.html) that is passed.&#x20;

Values must be positive integers.

Example:

{% tabs %}
{% tab title="Pug" %}

```pug
.test(
    width=100
    max-lines=1
    text-overflow='ellipsis')
    | Only one line gets shown, truncated
```

{% endtab %}

{% tab title="Dart" %}

```dart
DefaultTextStyle.merge( 
  child: 
  Container(
    child: Text( 
      'Only one line gets shown, truncated',
    ),
    width: 100,
  ),
  overflow: TextOverflow.ellipsis,
  maxLines: 1,
)
```

{% endtab %}
{% endtabs %}

## line-clamp <a href="#box-shadow" id="box-shadow"></a>

Alias for [**max-lines**](/reference/css-properties#box-shadow-19).

## display

CSS-like setting of how you want a widget to be displayed. This can be useful for removing layout elements through CSS.

Valid values:

* **none**: this will remove the widget

Example:

{% tabs %}
{% tab title="Pug" %}

```pug
.test
    .message(display="none") I never even become code
```

{% endtab %}

{% tab title="Dart" %}

```dart
//-- TEST ----------------------------------------------------------
Container(
)
```

{% endtab %}
{% endtabs %}

## &#x20;<a href="#box-shadow" id="box-shadow"></a>


