Skip to content

Instantly share code, notes, and snippets.

@jonschlinkert
Created November 8, 2012 16:32
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jonschlinkert/4039889 to your computer and use it in GitHub Desktop.
Save jonschlinkert/4039889 to your computer and use it in GitHub Desktop.
form mixin written in Pre

Pre

With Pre, you might create a form like this:

form.form-horizontal {
  action: "";
  .controlGroup();
  .controlGroup("Password");
  .controlGroupRememberMe();
}

and it would compile to this:

<form class="form-horizontal" action="">
  <div class="control-group">
    <label class="control-label" for="inputEmail">Email</label>
    <div class="controls">
      <input type="text" id="inputEmail" placeholder="Email">
    </div>
  </div>
  <div class="control-group">
    <label class="control-label" for="inputPassword">Password</label>
    <div class="controls">
      <input type="password" id="inputPassword" placeholder="Password">
    </div>
  </div>
  <div class="control-group">
    <div class="controls">
      <label class="checkbox">
        <input type="checkbox"> Remember me
      </label>
      <button type="submit" class="btn">Sign in</button>
    </div>
  </div>
</form>

This is made possible through the use of mixins...

Mixins

These mixins show how nicely Pre can simplify and DRY up code for repetitious elements like email and password inputs. The mixin can optionally have parameters or be easily modified to include "help text", etc.

Mixin for basic inputs

// This would probably be most appropriate when
// the mixin will have predictable parameters
.controlGroup(@text: "Email", @type: "Email", @for: "input"@{type}) {
  .control-group {
    label.control-label {
      for: @for;
      text: @text;
    }
    .controls {
      input {
        type: ~`@{type}.toLowerCase()`;
        id: @for;
        placeholder: @text;
      }
    }
  }
}

Mixin for a labeled checkbox and a button, with no paramaters

.controlGroupRememberMe() {
  .control-group {
    .controls {
      label.checkbox {
        input { type: "checkbox"; }
        text: "Remember me";
      }
      button.btn { 
        type: "submit";
        text: "Sign in";
      }
    }
  }
}

Mixin usage

In Pre, this is how you would add a form with mixins to a page.

form.form-horizontal {
  action: "";
  .controlGroup();
  .controlGroup("Password");
  .controlGroupRememberMe();
}

HTML output

And this is what would render from the previous example

<form class="form-horizontal" action="">
  <div class="control-group">
    <label class="control-label" for="inputEmail">Email</label>
    <div class="controls">
      <input type="text" id="inputEmail" placeholder="Email">
    </div>
  </div>
  <div class="control-group">
    <label class="control-label" for="inputPassword">Password</label>
    <div class="controls">
      <input type="password" id="inputPassword" placeholder="Password">
    </div>
  </div>
  <div class="control-group">
    <div class="controls">
      <label class="checkbox">
        <input type="checkbox"> Remember me
      </label>
      <button type="submit" class="btn">Sign in</button>
    </div>
  </div>
</form>

More Usage Examples

The possibilities here are endless...

form.form-horizontal {
  action: "";
  .form-header {
    h4 { text: "Sign in"}
  }
  .form-body {
    .controlGroup();
    .controlGroup("Password");
  }
  .form-actions {
    .controlGroupRememberMe();
  }
}

Or nest mixins:

.formActions(@buttonText: "Post") {
  a.button(@buttonText: "Sign up now", @type: "button") {
    text: @buttonText;
    type: @type;
  }
}

and use it like this:

form {
  .formHeader();
  .formBody();
  .formActions("Publish");
}

Or even turn that into a mixin:

form() {
  // declarations
}

and use it like this:

form();
@dpashkevich
Copy link

First of all, named mixin attributes are a must.

This is unreadable:

.field("Name", "firstname", "text", "Enter your name");

This is much better:

.field(label: "Name", name: "firstname", type: "text", placeholder: "Enter your name");

Even better:

.field(
    label: "Name",
    name: "firstname",
    type: "text", 
    placeholder: "Enter your name"
);

Besides, you may want to leave the freedom to additionally pass arbitrary HTML attributes to mixins, e.g.

.field(label: "Name", name: "firstname", id: "firstName", tabIndex: 5, disabled: true);

@dpashkevich
Copy link

About the semantics, I meant class names in form field markup. To be honest controls and controlGroup looks very confusing to me, especially the latter (sounds more like a set of several fields).

I would use classes like these:

.field {
    .field-label {...}
    .field-body {
        input {...}
        // possibly some extra elements
    }
}

I don't know when they added those control names to Bootstrap but they weren't there last time I looked...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment