DocsCLIPlaygroundAbout

Introduction

ftHTML is an HTML preprocessor built with basic webpages in mind to simplify markup and modularize elements. ftHTML supports 'forward typing syntax', importing other ftHTML files, variables and basic templates.

ftHTML is the SASS of CSS for HTML.

Even though ftHTML is a preprocessor, it also completely supports a static driven development cycle. You can develop offline and take advantage of a CLI to convert all ftHTML files to static HTML resources.

ftHTML is intended for all skill levels and all project scopes. It's easy to setup, understand and transition from regular HTML, yet it's powerful enough for seasoned developers who love modularizing their workspace and using variables and templates.

Forward Typing Syntax

Self proclaimed 'forward-typing syntax' is our effort in doing our best to eliminate the need to press backspace or spend valuable time typing special characters for tags to maintain a forward momentum. Without the use of something like emmet, typing the same identifier twice feels ambiguous to us, especially doing it countless times. We removed the need to do this:

<div>...</div>

to simply: 

div "..."

It's also our intent that the flow of typing is focused on things that matter, not unnecessary special characters.

Variables

Variables are our way of streamlining your most commonly used snippets. Variables can be defined and then used in your markup to easily re-use information, elements, layouts, attributes and more.

To define variables simply wrap their declarations and assignments in a vars pragma:

#vars

  animatedButtonClass 'btn btn-primary btn-lg animated'

  navLinks
    '<nav>
        <li><a href="home">Home</a></li>
        <li><a href="portfolio">Portfolio</a></li>
        <li><a href="about">About</a></li>
        <li><a href="contact">Contact</a></li>
     </nav>'

#end

You can then reference them in your markup, prefixing the variable name with an @ symbol:

body 
{
  header @navLinks

  main 
  {
    button (#backBtn .@animatedButtonClass) "Click Me!"
    button (#forwardBtn .@animatedButtonClass) "Click Me Too!"
  }

  footer @navLinks
}
<body>

  <header>
    <nav>
      <li><a href="home">Home</a></li>
      <li><a href="portfolio">Portfolio</a></li>
      <li><a href="about">About</a></li>
      <li><a href="contact">Contact</a></li>
    </nav>
  </header>

  <main>
    <button id="backBtn" class="btn btn-primary btn-lg animated">Click Me!</button>
    <button id="forwardBtn" class="btn btn-primary btn-lg animated">Click Me Too!</button>
  </main>

  <footer>
    <nav>
      <li><a href="home">Home</a></li>
      <li><a href="portfolio">Portfolio</a></li>
      <li><a href="about">About</a></li>
      <li><a href="contact">Contact</a></li>
    </nav>
  </footer>

</body>

Importing

You can easily import other .fthtml files into your markup by using the import keyword. Importing expects the file to have fthtml syntax and to be local in some fashion, meaning no http urls.

Importing can modularize your directory, encourages re-usability and simplifies your markup to be human-readable friendly. This also assists in keeping your markup in one convienent location should the chance arise you need to alter it, you would only have to make those changes in one place, one time.

For example, should all your files share the same header, we can define it in a specific file like the following examples:

CLI

We have included a feature heavy CLI with this package. The CLI is why this is recommended to be installed globally to take advantage of it's features

The CLI allows you to easily convert .fthtml files to static resources with just a single command. You can convert entire directories or individual files. You can omit entire directories as well to ensure effecient and prompt conversions.

A simple example of converting any .fthtml files in the root directory:

C:ProjectName> fthtml convert ./

Node.js

It's highly recommended to install this globally to take advantage of the CLI features

> npm i -g fthtml

Usage

const ftHTML = require('fthtml');
ftHTML.renderFile('index');

Getting Started

After you have installed ftHTML to your workspace globally, it’s time to think about file structure.

Although everyone has personal preferences when building file structures, we encourage those to maintain their preferences as it has no bearing on how ftHTML works. However, we have found that the best way to navigate and build out a folder structure is to keep it segregated from the HTML, and the other static files entirely. We found this works best because it doesn’t matter if you have a static driven project or a more dynamic project with something like express; it all flows just as fluid.

We recommend having ftHTML concepts in your dev folder with a dedicated ftHTML folder. We would recommend that folder to contain a imports dir and a templates dir.

Take the following Hello World project example with a root dir called ‘HelloWorld’:

HelloWorld
__.dev
    __.ftHTML
        __imports
            —header.ftHTML
            —footer.ftHTML
        __templates
            —head.ftHTML
        —index.ftHTML
__www
  __css
      —main.css

The benefit here is when you convert all your .ftHTML files, provided you are using a static driven development cycle, it’s easier syntax when it comes to importing and templating calls. The benefit for dynamic development using something like expressjs is that the files are stored on the server already, segregated from the static dir.

With a quick CLI command for static driven development we can convert those files and push them to the www dir:

C:DocumentsHelloWorld> fthtml convert ./.dev/.fthtml  --dest ./www -k

Hello World.

This tutorial will guide you through creating your first website with ftHTML! We’ll focus on the fundamental syntax and core components that make up ftHTML. You’ll learn how to create elements, children, variables and more. We’ll have a polished 'Hello World' website up and running within 10 minutes!

Before beginning make sure you have installed ftHTML globally on your machine. If you don’t know how to do that review our installation guide.

Download or clone the ftHTML HelloWorld repository to your local machine. We’ve included the css because it’s not really important for the scope of the tutorial, it just pretty’s things up!

Notice how we have the file structure. We find this good practice for how ftHTML works, so let’s just keep it that way for now and you can always change it to suit your needs later.

The 'import' dir is a place to store frequently used code snippets or just snippets used across different pages.

The templates dir is a place to store templates of pages that we can bind properties to that also get compiled.

Both of these folders will not be apart of our website as files, rather their content will be pulled into other files.


Let’s begin creating our website!

Step 1. Variables

In index.ftHTML, after the doctype declaration, let’s declare a variable! Variables are only allowed to be called in the file they are declared.

Lets create a variable called 'author' and set your name as the value. Variables can only be declared in the vars pragma.

doctype "html"

#vars
  author "username"
#end

Nothing else can go in a vars pragma except a variable name and it's value. You can declare as many as you like here!

Step 2. The Document Body

Great! Lets start building the structure of the page. Lets create our first element under our variables. Every HTML page needs an HTML tag. All ftHTML elements just need the name of the tag. However, when you want to add children you need to add curly braces { } after the tag name. You can think of the right curly brace } as htmls closing tag </html>. Let's add the HTML tag now.

doctype "html"

#vars
  author "username"
#end

html
{
  
}

Step 3. Templates

Every HTML page has a head tag as well where you can alter the title and other document attributes. This would be a great time to take advantage of templates. Navigate to .dev/.fthtml/templates and create a file called head.fthtml.

head
{
  title "Hello World" 
}

There's a small change we need to make to this template in order for it to bind a property. The syntax for string interpolation of variables and template properties is the following:

"${ <@variable/property> }"

Since every pages title could potentially be different this would be a great time to make the title the consumer of a binding property, we'll just call that property 'title':

head
{
  title "${ title }" 
}

As of now, string interpolation is the only way to display a property binded value.

Now we need to call this template back in index.ftHTML. Calling a template is just like a regular HTML tag, using the 'template' keyword:

template {
        
}

The complier at this point doesn't know where the template is located so let's import it using the 'import' keyword. Importing the file use's relative paths and always excludes the file extension:

template {
  import "./.dev/.fthtml/templates/head"
}

Now we need to bind to the title property we set. Property binding from the calling side is just like declaring variables. It expects a name and a string value, in this case we called it 'title'

template {
  import "./.dev/.fthtml/templates/head"
  title "Hello World"
}

As long as we use the template keyword properly this will pull the syntax we made in head.ftHTML into index.ftHTML and alter the title accordingly! Your index.ftHTML should now look like the following:

doctype "html"

#vars
  author "username"
#end

html
{
  template {
    import "./.dev/.fthtml/templates/head"
    title "Hello World"
  }
}

Step 4. Attributes

Let's go back to the head template so we can link our css sheet. Attributes for elements in ftHTML require them to be surrounded by a parenthesis set,( ) . Attributes are key value pairs just like regular HTML. Add the tag to link css.

head
{
  title "${ title }" 
  link(rel=stylesheet type="text/css" media=screen href="css/main.css")
}

Attribute values only require quotation marks if they have special characters.

Our css file is now linked to every page that calls this template and uses the title property!

Step 5. Document Body

Lets create our body element in index.ftHTML. You should have an idea of how to do this by now!

body {
      
}

Every page needs a header so lets create one. Since headers are usually the same thing across many pages this would be a good time to create an import. Navigate to the imports directory and add a file named 'header.ftHTML' and add the corresponding tag

header 
{
}

Lets add a navigation menu to the header:

header
{
  nav 
  {
    ul 
    {
      li "Home"
      li "About"
      li "Contact
    }
  }
}

Step 6. Imports

Now that we've created the header lets import it into our index.ftHTML file:

doctype "html"

#vars
  author "username"
#end

html
{
  template {
    import "./.dev/.fthtml/templates/head"
    title "Hello World"
  }

  body 
  {
    import "./.dev/.fthtml/imports/header"
  }
}

Step 7. Main Conent

Add a main tag to the body of the index.ftHTML file.

main
{
}

Lets add a simple heading to the main content that says "Hello World.", but let's give it an id. ftHTML has syntax sugar for classes and ids and the syntax sugar for an id is:

#<id_name>

Let's give it an id of 'main-title', but don't forget about the parenthesis since id's are an attribute!

doctype "html"

#vars
  author "username"
#end

html
{
  template {
    import "./.dev/.fthtml/templates/head"
    title "Hello World"
  }

  body 
  {
    import "./.dev/.fthtml/imports/header"

    main 
    {
      h1 (#main-title) "Hello World."
    }
  }
}

Let's add a horizontal line after the heading, but let's animate it using a class. The syntax sugar for classes is:

.<class_name>

Give it a class called 'animated'.

doctype "html"

#vars
  author "username"
#end

html
{
  template {
    import "./.dev/.fthtml/templates/head"
    title "Hello World"
  }

  body 
  {
    import "./.dev/.fthtml/imports/header"

    main 
    {
      h1 (#main-title) "Hello World"
      hr (.animated)
    }
  }
}

Let's add an h4 heading under the hr but use the author variable we declared earlier as it's value. If you remember how to use string interpolation from the templates section above you can apply the same lesson here; the difference is that when you call a variable you have to prefix it with an @ sybmol.

Let's write 'Made by <author> with ftHTML!'

doctype "html"

#vars
  author "username"
#end

html
{
  template {
    import "./.dev/.fthtml/templates/head"
    title "Hello World"
  }

  body 
  {
    import "./.dev/.fthtml/imports/header"

    main 
    {
      h1 (#main-title) "Hello World"
      hr (.animated)
      h4 "Made by ${ @author } with ftHTML!"
    }
  }
}

Just like a header, we'll need a footer to complete the main content. Navigate back to imports directory and create a file for a footer. The footer is largerly the same as the header and there are no new lessons learned, so copy and paste the following into that file:

footer
{
  div 
  {
    h5 "Links"
    nav 
    {
      ul {
        li "Home"
        li "About"
        li "Contact"
      }
    }    
  }

  p "copyright 2019 www.example.com"
}

Step 8. Convert your file

So far we've learned about declaring and calling variables, creating tags, attributes, id's, classes, templates and string interpolation. Most of the core components of ftHTML have been discussed and the only thing left is to learn about the CLI to convert your webpage.

Your complete project should look like the following:

To convert your file navigate to your projects root directory and type the following:

C:DocumentsftHTML_HelloWorld> fthtml convert ./

Congratulations! You've completed your first ftHTML website! You should see an index.html file in your root directory to open in your browser!

Syntax


Elements

Elements are defined by a valid token, optionally followed by a string for its value or a collection of other elements as its value

Syntax

<tag>
<tag> "<value>"
<tag> { ,[<...values>] }
<tag> ( ,[<...attrs>] )
<tag> ( ,[<...attrs>] ) { ,[<...values>] }

Requirements

The only requirement for an element to be valid is that it must meet the criteria of a valid tag name. Attributes or values are optional contributions

If a collection of elements (children) is provided, the collection must be enclosed in curly braces: { } Curly braces identify that the preceding tag is the parent of all the elements within the braces. Elements can be nested indefinetly. Elements can NOT have another element as its value without identifying it as a parent with the curly braces. For example div p "Hello World" will parse into:

<div></div>
<p>Hello World</p>

If attributes are provided for the element, the attributes must be enclosed in a parenthesis set: ( ). The attributes group should follow the tag immediately

Examples

//<tag>
div

// example of <tag> "<value>"
div "made with ftHTML"

// example of <tag> { ,[...values] }
div 
{
  h1 "Hello World"
  hr
  p "made with ftHTML"
}

// example of <tag> { ,[...attrs] }
div (data-target=someId data-attr-foo=bar title="tooltip title")
button (name=myButton autofocus value=myButtonValue)

// example of <tag> ( ,[...attrs] ) { ,[...values] }
div (data-target=someId title="tooltip title" disabled) 'made with ftHTML'
div (data-target=someId title="tooltip title" disabled) 
{
  p "made with ftHTML"
  button (name=myButton autofocus value=myButtonValue) "Ok"
}
// example of <tag>
<div></div>

// example of <tag> "<value>"
<div>made with ftHTML</div>

// example of <tag> { ,[...values] }
<div>
  <h1>Hello World</h1>
  <hr/>
  <p>Made with ftHTML</p>
</div>

// example of <tag> { ,[...attrs] }
<div data-target="someId" data-attr-foo="bar" title="tooltip title"></div>
<button name="myButton" autofocus value="myButtonValue"></button>

// example of <tag> ( ,[...attrs] ) { ,[...values] }
<div data-target="someId" title="tooltip title disabled">made with ftHTML</div>
<div data-target="someId" title="tooltip title disabled">
  <button name="myButton" autofocus value="myButtonValue">Ok</button>
</div>

Concacting Elements

Requirements

Elements can only be concactenated when siblings are children of the same element, meaning enclosed in a curly braces set: { }, as shown below.

Note: the + symbol has been deprecated as of Amaranth (v2.1) and is no longer valid syntax.

To concactenate strings with sibling elements, take this common example where you may want to include 2 links side by side with text in between:

div (#disclaimer) {
  "By clicking here you have read and agree to the " 
  a (href=tos.html) "Terms of Service" 
   " and " 
   a (href=pp.html) "Privacy Policies"
}
<div id="disclaimer">
  By clicking here you have read and agree to the <a href="tos.html">Terms of Service</a> and <a href="pp.html">Privacy Policies</a>.
</div>

Simply break out of the string and add the element of choice and continue where you left off

Tag Names


Tag names follow the pattern of html tag names ref with some slight modifications, while maintaining case-insensitive format

It can be visualed as such: [w-]+ meaning, any letter, digit, underscore or hyphen, one or more times. Equivalent to: [a-zA-Z0-9_-]+

Usage Notes

  • Element names are not converted to lowercase, all element names are parsed as-is

Keywords


Reserved Keywords

comment  doctype  end  import  vars  template
css      js       php

Usage Notes

  • Reserved keywords can not be used for variable definitions/names
  • Reserved keywords can not be used for element/tag names
  • Reserved keywords are case sensitive

Pragmas (Directives)


Pragmas are a way for you to communicate with the pre-processor in a way which extends the langauge. ftHTML utilizes the intent of pragmas to extend the language, as well as traditional control flow. Meaning, some pragmas may look different syntactically then you are used to, but still maintain the intent of pragmas.

Pragmas begin using the # symbol and end with a new line, EOF, or the correlating #end identifier, depending on the pragma

Usage Notes

  • Pragmas are not global and are scoped to their respective file/markup. Meaning they do not cascade into imports & templates
  • ftHTML pragmas are prescriptive and outlined below

#vars

Vars pragma is a specific region for declaring and instantiating variables. There are no restrictions where this pragma can be called

This pragma will exclusively be used to handle the respective files variables, meaning no other logic or markup will be accepted and this is the only region where it's allowed

Syntax

#vars 
  [<...variables>] 
#end

Requirements

A valid vars pragma must be closed by using the #end identifier

Examples

#vars
  myVar "Hello World"
#end

h1 @myVar
<h1>Hello World</h1>

Variables


Variables are a good way to quickly re-use frequently coded markup. You can call a variable once it's defined anywhere in the document and its value will be parsed as-is. The advantage of variables is that you can re-use the same content in many places but only have to declare/update it in one convient location

Syntax

Declaring
<variable_name> "<value>"
Referencing
@<variable_name>

Requirements

  • Must be declared within the vars pragma
  • Variable names must follow the same naming requirements as a tag name
  • Variables can not use another variable as it's name
  • When declaring a variable, it's value must exclusively be a string

Usage Notes

  • Variables can be re-instantiated at any time
  • Variables values are raw text elements, meaning parsed as-is

Examples

#vars 
   
  btn-common 'btn btn-lg btn-primary btn-animated'

  social-links    
      '<ul class="social">
        <li>Github</li>
        <li>Codepen</li>
      </ul>'

#end

header
{
  nav @social-links
}

div (#myId .@btn-common)
{
  "Hello World"
}

footer @social-links
<header>
  <nav>
    <ul class="social">
      <li>Github</li>
      <li>Codepen</li>
    </ul>
  </nav>
</header>

<div id="myId" class="btn btn-lg btn-primary btn-animated">Hello World</h1>

<footer>
  <ul class="social">
    <li>Github</li>
    <li>Codepen</li>
  </ul>
</footer>

Important

Because HTML5 allows for loose markup, it's impossible to plan for the countless ways a document can be formatted. Additionally, because ftHTML is a whitespace independent language, and in efforts to limit undesired results, it's always best to assume that when a variable follows an empty element then the variable is to be the preceding elements body (value). Take for example the footer @social-links value from the example above. Which could also be written as:

footer
@social-links

As it stands now, there is no way for the parser to know if you want:

<footer></footer>
<ul class="social">
  <li>Github</li>
  <li>Codepen</li>
</ul>

Or if you want the following:

<footer>
  <ul class="social">
    <li>Github</li>
    <li>Codepen</li>
  </ul>
</footer>

In our example it becomes the preceding elements body and works as desired, but if you want to ensure an element preceding a variable is parsed as an individual tag then it's recommended you enclose either of the elements in a wrapper. Take a common example, a horizontal line:

hr
@social-links

We want the hr to be parsed as a single tag and it's recommended to be written as something similar to the following:

hr
div @social-links

Or the following:

div { hr }

@social-links

Attributes


ftHTML attributes behave just like HTML attributes but is syntax sugar friendly

Attributes can be key/value pairs, variables, or individual elements.

Attribute values can be variables, variable values, strings or an HTML equivalent

Syntax

Syntax Sugar Attributes

Class
.<class_name>
Alternative Class - with variable
.@<variable_name>
Id
#<id_name>

Requirements

  • Syntax sugar is encouraged, but when an attribute value has special characters not allowed for element names or includes spaces, it's required to wrap that value in single or double quotes.
  • Attributes must be enclosed in a parenthesis group: ( )
  • An attribute group must follow an element (tag)

Usage Notes

  • There is no specific order attributes should be placed
  • Variables can be used in tandem
  • For attributes with syntax sugar, it is optional
  • If syntax sugar is used for syntax sugar friendly attributes, it does not merge it's counterpart. An example would be .className1 .className2 and class='className3' would parse into:
    <div class="className1 className2" class="className3" ></div>

Examples

div (.myClass #myId) "Hello World"

div (.myClass1 #myId .myClass2) "Hello World"

div (.myClass1 #myId readonly contenteditable) "Hello World"

a (href=www.google.com target=_blank data-attr=some_value) "Google"

//demonstrates special characters not allowed without quotes
a (href="../../somedir/about.html") "About Us"

//the following demonstrates variables as attributes
#vars

  btnCommon "btn btn-lg btn-primary btn-animated"
  styleCommon 'style="margin:0; padding: 0; overflow: hidden;"'

#end

div (#myId .@btnCommon @styleCommon) "Hello World"
<div class="myClass" id="myId">Hello World</div>

<div class="myClass1 myClass2" id="myId">Hello World</div>

<div class="myClass1" id="myId" readonly contenteditable>Hello World</div>

<a href="www.google.com" target="_blank" data-attr="some_value">Google</a>

//demonstrates special characters not allowed without quotes
<a href="../../somedir/about.html">About Us</a>

//the following demonstrates variables as attributes
<div id="myId" class="btn btn-lg btn-primary btn-animated" style="margin:0; padding: 0; overflow: hidden;">Hello World</div>

Comments


All comments are omitted when interpreting, except the DOM comment. DOM comments explicity ensure the comment renders in the HTML document, otherwise it's only for the developers eyes

Syntax

Line Comment
// <value>
Block Comment
/*
  [<...values>]
*/
DOM Comment
comment "<value>"

Requirements

Line comments must end with a new line character or at EOF

imports

Importing files acts as an easy way to write what we call 'soft templates', in the sense that you can't pass information into the 'template'. This is a file that can help separate markup, create a modularized project and include the same information across multiple files giving the advantage of only needing to update one instance of markup and keeping the infrastructure DRY

Syntax

import "<file_name>"

Requirements

  • Import statements only assume .ftHTML files
  • Imports will always assume and try to parse the file given, therefore an import files syntax should only be ftHTML syntax, otherwise it's recommended to use a variable, or template, to quickly re-use markup, ftHTML native or foreign
  • All import statements must exclude the extension name
  • If you wish to use an absolute path, for say a file out of project scope, you can but it must exclude the .ftHTML extension
  • Import filenames can not be remote url links

Examples

Templates

And Property Binding


Templates are a great way to quickly and easily import frequently used syntax.

ftHTML templates are flexible and promotes dynamic information via imports.

Templates are different than importants in that templates allow you to bind to a property, or many properties, to use across different pages for different needs.

Syntax

Declaring a binding property in a template file:
"${ <property_name> }"
Declaring a null safe binding property in a template file:
"${ <property_name>? }"
Referencing the template file and setting the value of a property:
template {
  import "<file_name>"
  <binding_property> "<value>"
}

Requirements

  • Binding properties can only be declared in a string using interpolation
  • When declaring a property via interpolation, it is expecting a single property name.
  • The parser doesn't know what template to use, therefore an 'import' statement is required for each template reference to specify

Usage Notes

  • Binding properties do not support complex operations or logic, as noted, the interpolation syntax is strictly expecting a single value.
  • There is no limit to amount of binding properties per template
  • Null safe binding properties allow the template to be imported without setting the value of a particular property

Example

Embedded Languages


The embedded languages feature allows for an easy way to incorporate other languages/markup into your ftHTML files

Embedded language tags allow raw input, as-is, for it's respective language. The parser does not restrict syntax to ftHTML syntax for embedded language tags.

Currently, the supported embedded language tags are:

css      js       php

Syntax

<lang_name> {
  ...
}

Requirements

  • Embedded language tag names are case sensitive and can not be used as variables or other element names
  • Embedded language tags do not support attributes

Usage Notes

  • If you are using the vscode ftHTML extension, embedded lanugage tags support syntax highlighting for the respective language
  • You can not nest embedded languages since raw input is strictly expected
  • PHP tag supports all string types, including heredoc and nowdoc

Examples

html
{
  head 
  {
    title 'Home'
    script(src='https://code.jquery.com/jquery-3.4.1.min.js')

    css {
      * { box-sizing: border-box;}

      body, html {
        width: 100%; height: 100%;
      }

      h1 {
        color: tomato;
        font-size: 3rem;
      }
    }
  }

  body 
  {
    h1 'Hello World'
  }
}
html
{
  head 
  {
    title 'Home'
    script(src='https://code.jquery.com/jquery-3.4.1.min.js')
  }

  body 
  {
    h1 'Hello World'
  }

  js {
    $('h1').css('font-size', '3rem');
  }
}

String Interpolation


String interpolation is pretty straight forward. It emulates a template literal in javascript.

Syntax

Variable
"... ${ @<variable_name> } ..."
Binding Property
"... ${ <property_name> } ..."

Usage Notes

  • Interpolation is currently the only way to parse a value of property binding
  • ftHTML interpolation doesn't support complex logic operations or statements. It expects a single variable or a single property name.
  • Interpolation does not support regular text or another string

Examples

#vars
  author "john doe"
#end

h1 "Created by ${ @author }"