mdgriffith/stylish-elephants/3.0.0

NOTE: this package is not compatible with Elm 0.19.1

Element

Basic Elements

type alias Element msg =
Element msg

The basic building block of your layout. Here we create a

import Background
import Element


view =
    Element.el [] (Element.text "Hello!")
type alias Attribute msg =
Attribute msg
empty : Element msg

Nothing to see here!

text : String -> Element msg

Create some plain text.

text "Hello, you stylish developer!"

Note text does not wrap by default. In order to get text to wrap, check out paragraph!

el : List (Attribute msg) -> Element msg -> Element msg

The basic building block of your layout.

import Color exposing (blue, darkBlue)
import Element exposing (Element)
import Element.Background as Background
import Element.Border as Border


myElement : Element msg
myElement =
    Element.el
        [ Background.color blue
        , Border.color darkBlue
        ]
        (Element.text "You've made a stylish element!")

Rows and Columns

Rows and columns are the most common layouts.

row : List (Attribute msg) -> List (Element msg) -> Element msg

If you want a row of elements, use row!

column : List (Attribute msg) -> List (Element msg) -> Element msg

Text Layout

Text needs it's own layout primitives.

paragraph : List (Attribute msg) -> List (Element msg) -> Element msg

A paragraph will layout all children as wrapped, inline elements.

import Element
import Element.Font as Font


Element.paragraph []
    [ text "lots of text ...."
    , el [ Font.bold ] (text "this is bold")
    , text "lots of text ...."
    ]

This is really useful when you want to markup text by having some parts be bold, or some be links, or whatever you so desire.

Also, if a child element has alignLeft or alignRight, then it will be moved to that side and the text will flow around it, (ah yes, float behavior).

This makes it particularly easy to do something like a dropped capital.

import Element
import Element.Font as Font


Element.paragraph []
    [ el
        [ alignLeft
        , padding 5
        , Font.lineHeight 1
        ]
        (text "S")
    , text "lots of text ...."
    ]

Which will look something like

textColumn : List (Attribute msg) -> List (Element msg) -> Element msg

Now that we have a paragraph, we need someway to attach a bunch of paragraph's together.

To do that we can use a textColumn.

The main difference between a column and a textColumn is that textColumn will flow the text around elements that have alignRight or alignLeft, just like we just saw with paragraph.

In the following example, we have a textColumn where one child has alignLeft.

Elment.textColumn [ spacing 10, padding 10 ]
    [ paragraph [] [ text "lots of text ...." ]
    , el [ alignLeft ] empty
    , paragraph [] [ text "lots of text ...." ]
    ]

Which will result in something like:

Data Table

type alias Table records msg =
{ data : List records
, columns : List (Column records msg)
}
type alias Column record msg =
{ header : Element msg
, view : record -> Element msg
}
table : List (Attribute msg) -> Table data msg -> Element msg

Show some tabular data.

Start with a list of records and specify how each column should be rendered.

So, if we have a list of persons:

type alias Person =
    { firstName : String
    , lastName : String
    }


persons : List Person
persons =
    [ { firstName = "David"
      , lastName = "Bowie"
      }
    , { firstName = "Florence"
      , lastName = "Welch"
      }
    ]

We could render it using

Element.table []
    { data = persons
    , columns =
        [ { header = Element.text "First Name"
          , view =
                (\person ->
                    Element.text person.firstName
                )
          }
        , { header = Element.text "Last Name"
          , view =
                 (\person ->
                    Element.text person.lastName
                 )
          }
        ]
    }

Rendering

layout : List (Attribute msg) -> Element msg -> Html msg

This is your top level node where you can turn Element into Html.

{ options : List Option }
-> List (Attribute msg)
-> Element msg
-> Html msg
type alias Option =
Option
forceHover : Option

Any hover styles, aka attributes with mouseOver in the name, will be always turned on.

This is useful for when you're targeting a platform that has no mouse, such as mobile.

noHover : Option

Disable all mouseOver styles.

focusStyle : FocusStyle -> Option
type alias FocusStyle =
{ borderColor : Maybe Color
, backgroundColor : Maybe Color
, shadow :
Maybe
{ color : Color
, offset : ( Int, Int )
, blur : Int
, size : Int
}
}

Links and Images

download : List (Attribute msg) -> Link msg -> Element msg

A link to download a file.

List (Attribute msg)
-> { label : Element msg
, filename : String
, url : String
}
-> Element msg

A link to download a file, but you can specify the filename.

List (Attribute msg)
-> { src : String
, description : String
}
-> Element msg

Both a source and a description are required for images. The description is used to describe the image to screen readers.

decorativeImage : List (Attribute msg) -> { src : String } -> Element msg

If an image is purely decorative, you can skip the caption.

Attributes

type alias Attribute msg =
Attribute msg
hidden : Bool -> Attribute msg
description : String -> Attribute msg
pointer : Attribute msg

Set the cursor to the pointer hand.

Width and Height

width : Length -> Attribute msg
height : Length -> Attribute msg
type alias Length =
Length
px : Int -> Length
shrink : Length
fill : Length

Fill the available space. The available space will be split evenly between elements that have width fill.

fillPortion : Int -> Length

Sometimes you may not want to split available space evenly. In this case you can use fillPortion to define which elements should have what portion of the available space.

So, two elements, one with width (fillPortion 2) and one with width (fillPortion 3). The first would get 2 portions of the available space, while the second would get 3.

Also: fill == fillPortion 1

Padding and Spacing

There's no concept of margin in style-elements, instead we have padding and spacing.

Padding is what you'd expect, the distance between the outer edge and the content, and spacing is the space between children.

So, if we have the following row, with some padding and spacing.

Element.row [ padding 10, spacing 7 ]
    [ Element.el [] empty
    , Element.el [] empty
    , Element.el [] empty
    ]

Here's what we can expect.

Three boxes spaced 7 pixels apart.  There's a 10 pixel distance from the edge of the parent to the boxes.
padding : Int -> Attribute msg
paddingXY : Int -> Int -> Attribute msg

Set horizontal and vertical padding.

{ bottom : Int
, left : Int
, right : Int
, top : Int
}
-> Attribute msg
spacing : Int -> Attribute msg
spacingXY : Int -> Int -> Attribute msg

In the majority of cases you'll just need to use spacing, which will work as intended.

However for some layouts, like textColumn, you may want to set a different spacing for the x axis compared to the y axis.

spaceEvenly : Attribute msg

Alignment

Alignment can be used to align an Element within another Element.

Element.el [ center, alignTop ] (text "I'm centered and aligned top!")

If alignment is set on elements in a layout such as row, then the element will push the other elements in that direction. Here's an example.

Element.row []
    [ Element.el [] Element.empty
    , Element.el [ alignLeft ] Element.empty
    , Element.el [ center ] Element.empty
    , Element.el [ alignRight ] Element.empty
    ]

will result in a layout like

|-|-| |-| |-|

Where there are two elements on the left, one in the center, and on on the right.

center : Attribute msg
centerY : Attribute msg
alignLeft : Attribute msg
alignRight : Attribute msg
alignTop : Attribute msg
alignBottom : Attribute msg

Nearby Elements

It can be nice to position an element relative to another element, _without

Let's say we want a dropdown menu. Essentially we want to say: put this element below this other element, but don't affect the layout when you do.

Elemenet.row []
    [ Element.el
        [ Element.below True (Element.text "I'm below!")
        ]
        (Element.text "I'm normal!")
    ]

This will result in

|- I'm normal! -|
   I'm below

Where "I'm Below" doesn't change the size of Element.row.

This is very useful for things like dropdown menus or tooltips.

above : Bool -> Element msg -> Attribute msg

above takes a Bool first so that you can easily toggle showing and hiding the element.

below : Bool -> Element msg -> Attribute msg
onRight : Bool -> Element msg -> Attribute msg
onLeft : Bool -> Element msg -> Attribute msg
inFront : Bool -> Element msg -> Attribute msg
behind : Bool -> Element msg -> Attribute msg

Adjustment

moveRight : Float -> Attribute msg
moveUp : Float -> Attribute msg
moveLeft : Float -> Attribute msg
moveDown : Float -> Attribute msg
rotate : Float -> Attribute msg
scale : Float -> Attribute msg
mouseOverScale : Float -> Attribute msg

Clipping and Scrollbars

Clip the content if it overflows.

clip : Attribute msg
clipX : Attribute msg
clipY : Attribute msg

If these are present, the element will add a scrollbar if necessary.

scrollbars : Attribute msg
scrollbarY : Attribute msg
scrollbarX : Attribute msg

Mapping

map : (msg -> msg1) -> Element msg -> Element msg1
mapAttribute : (msg -> msg1) -> Attribute msg -> Attribute msg1

Compatibility

html : Html msg -> Element msg
attribute : Attribute msg -> Attribute msg