All Projects → westonganger → form_builder.cr

westonganger / form_builder.cr

Licence: MIT license
Dead simple HTML form builder for Crystal with built-in support for many popular UI libraries such as Bootstrap

Programming Languages

crystal
512 projects

Projects that are alternatives of or similar to form builder.cr

sexy form.rb
Dead simple HTML form field builder for Ruby with built-in support for many popular UI libraries such as Bootstrap
Stars: ✭ 38 (+31.03%)
Mutual labels:  form-builder, html-form, html-form-builder
fluence
WYSIWYG wiki powered by Crystal, markdown, and Git
Stars: ✭ 44 (+51.72%)
Mutual labels:  crystal-lang
react-quizzes
A React.js solution that offers a UI for creating surveys, forms and quizzes.
Stars: ✭ 25 (-13.79%)
Mutual labels:  form-builder
typiform
⚛️ A serverless React powered online form builder that works like a doc.
Stars: ✭ 16 (-44.83%)
Mutual labels:  form-builder
antd-react-form-builder
Example
Stars: ✭ 74 (+155.17%)
Mutual labels:  form-builder
react-declarative
A React form builder which interacts with a JSON endpoint to generate nested 12-column grids with input fields and automatic state management in a declarative style. Endpoint is typed by TypeScript guards (IntelliSense available). This tool is based on material-ui components, so your application will look beautiful on any device...
Stars: ✭ 17 (-41.38%)
Mutual labels:  form-builder
gutenberg-forms
The Next Generation WordPress Form Builder.
Stars: ✭ 98 (+237.93%)
Mutual labels:  form-builder
formToObject.js
Convert a HTML form to a JS literal (multidimensional) object.
Stars: ✭ 87 (+200%)
Mutual labels:  html-form
element-schema-form
A schema-based element-ui form component for Vue2.x.
Stars: ✭ 31 (+6.9%)
Mutual labels:  form-builder
react-cool-form
😎 📋 React hooks for forms state and validation, less code more performant.
Stars: ✭ 246 (+748.28%)
Mutual labels:  form-builder
django-siteforms
Django reusable app to simplify form construction
Stars: ✭ 15 (-48.28%)
Mutual labels:  form-builder
con
A simple, fast and readable JSON-compatible serialization format
Stars: ✭ 22 (-24.14%)
Mutual labels:  crystal-lang
fayrant-lang
Simple, interpreted, dynamically-typed programming language
Stars: ✭ 30 (+3.45%)
Mutual labels:  crystal-lang
html
🔨 HTML and Form Builders for the Laravel Framework
Stars: ✭ 34 (+17.24%)
Mutual labels:  form-builder
aquaplot
AquaPlot is a data visualization library for crystal-lang (https://crystal-lang.org/). Currently in very early development and the API is not at all stable.
Stars: ✭ 31 (+6.9%)
Mutual labels:  crystal-lang
tput.cr
Low-level component for building term/console applications in Crystal
Stars: ✭ 22 (-24.14%)
Mutual labels:  crystal-lang
joobq
JoobQ is a fast, efficient asynchronous reliable job queue and job scheduler library processing. Jobs are submitted to a job queue, where they reside until they are able to be scheduled to run in a computing environment.
Stars: ✭ 26 (-10.34%)
Mutual labels:  crystal-lang
yii2-formbuilder
A drag and drop form builder with jQuery for Yii2
Stars: ✭ 33 (+13.79%)
Mutual labels:  form-builder
tdiff
CLI tool for comparing tree like structures
Stars: ✭ 20 (-31.03%)
Mutual labels:  crystal-lang
crystal-validator
💎 Data validation module for Crystal lang
Stars: ✭ 23 (-20.69%)
Mutual labels:  crystal-lang

Form Builder.cr

Version CI Status Buy Me a Coffee

Dead simple HTML form builder for Crystal with built-in support for many popular UI libraries such as Bootstrap. Works well with your favourite Crystal web framework such as Kemal, Amber, or Lucky.

Features

  • Easily generate HTML markup for forms, labels, inputs, help text and errors
  • Integrates with many UI libraries such as Bootstrap
  • Custom theme support

Supported UI Libraries

Out of the box Form Builder can generate HTML markup for the following UI libraries:

  • Bootstrap 4
    • theme: :bootstrap_4_vertical
    • theme: :bootstrap_4_inline
    • theme: :bootstrap_4_horizontal or theme: FormBuilder::Themes::Bootstrap4Horizontal.new(column_classes: ["col-sm-3","col-sm-9"])
  • Bootstrap 3
    • theme: :bootstrap_3_vertical
    • theme: :bootstrap_3_inline
    • theme: :bootstrap_3_horizontal or theme: FormBuilder::Themes::Bootstrap3Horizontal.new(column_classes: ["col-sm-3","col-sm-9"])
  • Bootstrap 2
    • theme: :bootstrap_2_vertical
    • theme: :bootstrap_2_inline
    • theme: :bootstrap_2_horizontal
  • Bulma
    • theme: :bulma_vertical
    • theme: :bulma_horizontal
  • Foundation
    • theme: :foundation
  • Materialize
    • theme: :materialize
  • Milligram
    • theme: :milligram
  • Semantic UI
    • theme: :semantic_ui_vertical
    • theme: :semantic_ui_inline
  • None (Default)
    • theme: :default
    • theme: nil
    • or simply do not provide a :theme argument

If you dont see your favourite UI library here feel free to create a PR to add it. I recommend creating an issue to discuss it first.

Installation

Add this to your application's shard.yml:

dependencies:
  form_builder:
    github: westonganger/form_builder.cr
require "form_builder"

Usage

The following field types are supported:

  • :checkbox
  • :file
  • :hidden
  • :password
  • :radio
  • :select
  • :text
  • :textarea

FormBuilder in View Templates (Example in Slang)

== FormBuilder.form(theme: :bootstrap_4_vertical, action: "/products", method: :post, form_html: {style: "margin-top: 20px;", "data-foo" => "bar"}) do |f|
  .row.main-examples
    .col-sm-6
      ### -- Field Options
      ### type : (String | Symbol)
      ### name : (String | Symbol)?
      ### label : (String | Bool)? = true
      ### help_text : String?

      ### value : (String | Symbol)?
      ### -- Note: The `input_html["value"]` option will take precedence over the :value option (except for `type: :textarea/:select`)

      ### errors : (Array(String) | String)?
      ### -- Note: Array(String) generates a list of help text elements. If you have an Array of errors and you only want a single help text element, then join your errors array to a String

      ### -- For the following Hash options, String keys will take precedence over any Symbol keys
      ### input_html : (Hash | NamedTuple)? ### contains attributes to be added to the input/field
      ### label_html : (Hash | NamedTuple)? ### contains attributes to be added to the label
      ### wrapper_html : (Hash | NamedTuple)? ### contains attributes to be added to the outer wrapper for the label and input
      ### help_text_html : (Hash | NamedTuple)? ### contains attributes to be added to the help text container
      ### error_html : (Hash | NamedTuple)? ### contains attributes to be added to the error container(s) 
 
      == f.field name: "product[name]", label: "Name", type: :text, errors: product_errors["name"]

      == f.field name: "product[description]", label: "Description", type: :textarea, input_html: {class: "foobar"}, wrapper_html: {style: "margin-top: 10px"}, label_html: {style: "color: red;"}

      == f.field name: "product[file]", type: :file, help_text: "Must be a PDF", help_text_html: {style: "color: blue;"}

    .col-sm-6
      == f.field name: "product[available]", type: :checkbox, label: "In Stock?"

      == f.field name: "product[class]", type: :radio, label: false

      == f.field name: "product[secret]", type: :hidden, value: "foobar"

  .row.select-example
    ### -- Additional Options for `type: :select`
    ### collection : (Hash | NamedTuple) = {
    ###   options : (Array(String) | Array(String | Array(String)) | String) ### Required, Note: The non-Array String type is for passing in a pre-built html options string
    ###   selected : (String | Array(String))?
    ###   disabled : (String | Array(String))?
    ###   include_blank : (String | Bool)?
    ### }
    ### -- Note: String keys will take precedence over any Symbol keys

    ### -- When passing a nested array to collection[:options] the Option pairs are defined as: [required_value, optional_label]
    - opts = [["A", "Type A"], ["B" "Type B"], ["C", "Type C"], "Other"]

    == f.field name: "product[type]", label: "Type", type: :select, collection: {options: opts, selected: ["B"], disabled: ["C"]}

FormBuilder in Plain Crystal Code

When using the FormBuilder.form method in plain Crystal code, the << syntax is required to add the generated field HTML to the form HTML string

form_html_str = FormBuilder.form(theme: :bootstrap_4_vertical, action: "/products", method: :post, form_html: {style: "margin-top: 20px;", "data-foo" => "bar"}) do |f|
  f << f.field(name: "name", type: :text, label: "Name")
  f << f.field(name: "sku", type: :text, label: "SKU")
  f << "<strong>Hello World</strong>"
end

OR you can use the lower level String.build instead:

form_html_str = String.build do |str|
  str << FormBuilder.form(theme: :bootstrap_4_vertical, action: "/products", method: :post, form_html: {style: "margin-top: 20px;", "data-foo" => "bar"}) do |f|
    str << f.field(name: "name", type: :text, label: "Name")
    str << f.field(name: "sku", type: :text, label: "SKU")
    str << "<strong>Hello World</strong>"
  end
end

FormBuilder without a Form

- f = FormBuilder::Builder.new(theme: :bootstrap_4_vertical)

== f.field name: "name", type: :text, label: "Name"
== f.field name: "sku", type: :text, label: "SKU"

Error Handling

The form builder is capable of handling error messages too. If the :errors argument is provided it will generate the appropriate error help text element(s) next to the field.

== FormBuilder.form(theme: :bootstrap_4_vertical) do |f|
  == f.field name: "name", type: :text, label: "Name", errors: "cannot be blank"
  == f.field name: "sku", type: :text, label: "SKU", errors: ["must be unique", "incorrect SKU format")

Custom Themes

FormBuilder allows you to create custom themes very easily.

Example Usage:

FormBuilder.form(theme: :custom)

Example Theme Class:

# config/initializers/form_builder.cr

module FormBuilder
  module Themes
    class Custom < BaseTheme

      ### (Optional) If your theme name doesnt perfectly match the `.underscore` of the theme class name
      def self.theme_name
        "custom"
      end

      ### (Optional) If your theme requires additional variables similar to `Bootstrap3Horizontal.new(columns: ["col-sm-3", "col-sm-9"])`
      def initialize
        ### For an example see `src/form_builders/themes/bootstrap_3_horizontal.cr`
      end

      def wrap_field(field_type : String, html_field : String, html_label : String?, html_help_text : String?, html_errors : Array(String)?, wrapper_html_attributes : StringHash)
        String.build do |s|
          wrapper_html_attributes["class"] = "form-group #{wrapper_html_attributes["class"]?}".strip

          ### `FormBuilder.build_html_attr_string` is the one and only helper method for Themes
          ### It converts any Hash to an HTML Attributes String
          ### Example: {"class" => "foo", "data-role" => "ninja"} converts to "class=\"foo\" data-role=\"ninja\""
          attr_str = FormBuilder.build_html_attr_string(wrapper_html_attributes)

          s << "#{attr_str.empty? ? "<div>" : %(<div #{attr_str}>)}"

          if {"checkbox", "radio"}.includes?(field_type) && html_label && (i = html_label.index(">"))
            s << html_label.insert(i+1, "#{html_field} ")
          else
            s << html_label
            s << html_field
          end
          
          s << html_help_text

          if html_errors
            s << html_errors.join
          end

          s << "</div>"
        end
      end

      def input_html_attributes(html_attrs : Hash(String, String), field_type : String, has_errors? : Bool)
        html_attrs["class"] = "form-field other-class #{html_attrs["class"]?}".strip
        html_attrs["style"] = "color: blue; #{html_attrs["style"]?}".strip
          
        unless html_attrs.has_key?("data-foo")
          html_attrs["data-foo"] = "bar #{html_attrs["class"]?}"
        end
        
        html_attrs
      end

      def label_html_attributes(html_attrs : Hash(String, String), field_type : String, has_errors? : Bool)
        html_attrs["class"] = "form-label other-class #{html_attrs["class"]?}".strip
        html_attrs["style"] = "color: red; #{html_attrs["style"]?}".strip
        html_attrs
      end

      def form_html_attributes(html_attrs : Hash(String, String))
        html_attrs["class"] = "form-inline #{html_attrs["class"]}"
        html_attrs
      end

      def build_html_help_text(help_text : String, html_attrs : StringHash)
        html_attrs["class"] = "help-text #{html_attrs["class"]?}".strip

        String.build do |s|
          s << (html_attrs.empty? ? "<div>" : %(<div #{build_html_attr_string(html_attrs)}>)
          s << help_text
          s << "</div>"
        end
      end

      def build_html_error(error : String, html_attrs : StringHash)
        html_attrs["class"] = "help-text error #{html_attrs["class"]?}".strip
        html_attrs["style"] = "color: red; #{html_attrs["style"]?}".strip

        String.build do |s|
          s << (html_attrs.empty? ? "<div>" : %(<div #{build_html_attr_string(html_attrs)}>)
          s << error
          s << "</div>"
        end
      end

    end
  end
end

Now you can use the theme just like any other built-in theme.

FormBuilder.form(theme: :custom)

Contributing

To run the test suite:

crystal spec

Ruby Alternative

This library has been ported to the Ruby language as SexyForm.rb

The pattern/implementation of this form builder library turned out so beautifully that I felt the desire to have the same syntax available in the Ruby language. Many Crystal developers also write Ruby and vice versa so this only made sense. What was awesome is that, the Crystal and Ruby syntax is so similar that converting Crystal code to Ruby was straight forward and quite simple.

Credits

Created & Maintained by Weston Ganger - @westonganger

For any consulting or contract work please contact me via my company website: Solid Foundation Web Development

Solid Foundation Web Development Logo

Project Inspired By:

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].