Orasund / elm-ui-widgets / Widget

This module contains different stateless view functions. No wiring required.

Widget.button Material.primaryButton
    { text = "disable me"
    , icon =
        FeatherIcons.slash
            |> FeatherIcons.withSize 16
            |> FeatherIcons.toHtml []
            |> Element.html
            |> Element.el []
    , onPress =
        if isButtonEnabled then
            ChangedButtonStatus False
                |> Just

        else
            Nothing
    }

Every widgets comes with a type. You can think of the widgets as building blocks. You can create you own widgets by sticking widgets types together.

Buttons

Button


type alias ButtonStyle msg =
{ elementButton : List (Element.Attribute msg)
, ifDisabled : List (Element.Attribute msg)
, ifActive : List (Element.Attribute msg)
, otherwise : List (Element.Attribute msg)
, content : { elementRow : List (Element.Attribute msg)
, content : { text : { contentText : List (Element.Attribute msg) }
, icon : { ifDisabled : IconStyle
, ifActive : IconStyle
, otherwise : IconStyle } } } 
}


type alias Button msg =
{ text : String
, icon : Icon msg
, onPress : Maybe msg 
}

Button widget type


type alias TextButton msg =
{ text : String
, onPress : Maybe msg 
}

Button widget type with no icon

iconButton : ButtonStyle msg -> { text : String, icon : Icon msg, onPress : Maybe msg } -> Element msg

A button containing only an icon, the text is used for screen readers.

import Widget.Material as Material
import Material.Icons as MaterialIcons
import Material.Icons.Types exposing (Coloring(..))
import Widget.Icon as Icon

type Msg
    = Like

iconButton (Material.iconButton Material.defaultPalette)
    { text = "Like"
    , icon = MaterialIcons.favorite |> Icon.elmMaterialIcons Color
    , onPress = Just Like
    }
    |> always "Ignore this line" --> "Ignore this line"

textButton : ButtonStyle msg -> { textButton | text : String, onPress : Maybe msg } -> Element msg

A button with just text and not icon.

import Widget.Material as Material

type Msg
    = Like

textButton (Material.textButton Material.defaultPalette)
    { text = "Like"
    , onPress = Just Like
    }
    |> always "Ignore this line" --> "Ignore this line"

button : ButtonStyle msg -> { text : String, icon : Icon msg, onPress : Maybe msg } -> Element msg

A button containing a text and an icon.

import Widget.Material as Material
import Material.Icons as MaterialIcons
import Material.Icons.Types exposing (Coloring(..))
import Widget.Icon as Icon

type Msg
    = Submit

button (Material.containedButton Material.defaultPalette)
    { text = "Submit"
    , icon = MaterialIcons.favorite |> Icon.elmMaterialIcons Color
    , onPress = Just Submit
    }
    |> always "Ignore this line" --> "Ignore this line"

Checkbox

Checkbox


type alias CheckboxStyle msg =
{ elementButton : List (Element.Attribute msg)
, ifDisabled : List (Element.Attribute msg)
, ifSelected : List (Element.Attribute msg)
, ifDisabledSelected : List (Element.Attribute msg)
, otherwise : List (Element.Attribute msg) 
}


type alias Checkbox msg =
{ description : String
, onChange : Maybe (Basics.Bool -> msg)
, checked : Basics.Bool 
}

A checkbox

checkbox : CheckboxStyle msg -> { description : String, onChange : Maybe (Basics.Bool -> msg), checked : Basics.Bool } -> Element msg

A checkbox button

import Widget.Material as Material

type Msg
    = Check Bool

checkbox (Material.checkbox Material.defaultPalette)
    { description = "Dark Mode"
    , onChange = Just Check
    , checked = False
    }
    |> always "Ignore this line" --> "Ignore this line"

Radio

Radio


type alias RadioStyle msg =
{ elementButton : List (Element.Attribute msg)
, ifDisabled : List (Element.Attribute msg)
, ifSelected : List (Element.Attribute msg)
, ifDisabledSelected : List (Element.Attribute msg)
, otherwise : List (Element.Attribute msg)
, content : { element : List (Element.Attribute msg)
, ifDisabled : List (Element.Attribute msg)
, ifSelected : List (Element.Attribute msg)
, ifDisabledSelected : List (Element.Attribute msg)
, otherwise : List (Element.Attribute msg) } 
}

Radio style type


type alias Radio msg =
{ description : String
, onPress : Maybe msg
, selected : Basics.Bool 
}

Radio widget type

radio : RadioStyle msg -> { description : String, onPress : Maybe msg, selected : Basics.Bool } -> Element msg

A radio button

import Widget.Material as Material

type Msg
    = Activate

radio (Material.radio Material.defaultPalette)
    { description = "Dark Mode"
    , onPress = Just Activate
    , selected = False
    }
    |> always "Ignore this line" --> "Ignore this line"

Switch

Switch


type alias SwitchStyle msg =
{ elementButton : List (Element.Attribute msg)
, content : { element : List (Element.Attribute msg)
, ifDisabled : List (Element.Attribute msg)
, ifActive : List (Element.Attribute msg)
, otherwise : List (Element.Attribute msg) }
, contentInFront : { element : List (Element.Attribute msg)
, ifDisabled : List (Element.Attribute msg)
, ifActive : List (Element.Attribute msg)
, otherwise : List (Element.Attribute msg)
, content : { element : List (Element.Attribute msg)
, ifDisabled : List (Element.Attribute msg)
, ifActive : List (Element.Attribute msg)
, otherwise : List (Element.Attribute msg) } } 
}


type alias Switch msg =
{ description : String
, onPress : Maybe msg
, active : Basics.Bool 
}

Switch widget type

switch : SwitchStyle msg -> { description : String, onPress : Maybe msg, active : Basics.Bool } -> Element msg

A boolean switch

import Widget.Material as Material

type Msg
    = Activate

switch (Material.switch Material.defaultPalette)
    { description = "Activate Dark Mode"
    , onPress = Just Activate
    , active = False
    }
    |> always "Ignore this line" --> "Ignore this line"

Select

Select


type alias Select msg =
{ selected : Maybe Basics.Int
, options : List { text : String
, icon : Icon msg }
, onSelect : Basics.Int -> Maybe msg 
}

Select widget type

Technical Remark:

selectButton : ButtonStyle msg -> ( Basics.Bool, Button msg ) -> Element msg

A simple button that can be selected.

import Widget.Material as Material
import Element

type Msg
    = ChangedSelected Int

{ selected = Just 1
, options =
    [ 1, 2, 42 ]
        |> List.map
            (\int ->
                { text = String.fromInt int
                , icon = always Element.none
                }
            )
, onSelect = (\i -> Just <| ChangedSelected i)
}
    |> Widget.select
    |> Widget.buttonRow
        { elementRow = Material.buttonRow
        , content = Material.outlinedButton Material.defaultPalette
        }
    |> always "Ignore this line" --> "Ignore this line"

select : Select msg -> List ( Basics.Bool, Button msg )

Selects one out of multiple options. This can be used for radio buttons or Menus.

import Widget.Material as Material
import Element

type Msg
    = ChangedSelected Int

{ selected = Just 1
, options =
    [ 1, 2, 42 ]
        |> List.map
            (\int ->
                { text = String.fromInt int
                , icon = always Element.none
                }
            )
, onSelect = (\i -> Just <| ChangedSelected i)
}
    |> Widget.select
    |> Widget.buttonRow
        { elementRow = Material.buttonRow
        , content = Material.toggleButton Material.defaultPalette
        }
    |> always "Ignore this line" --> "Ignore this line"


type alias MultiSelect msg =
{ selected : Set Basics.Int
, options : List { text : String
, icon : Icon msg }
, onSelect : Basics.Int -> Maybe msg 
}

Multi Select widget type

Technical Remark:

multiSelect : MultiSelect msg -> List ( Basics.Bool, Button msg )

Selects multiple options. This can be used for checkboxes.

import Widget.Material as Material
import Set
import Element

type Msg
    = ChangedSelected Int

{ selected = [1,2] |> Set.fromList
, options =
    [ 1, 2, 42 ]
        |> List.map
            (\int ->
                { text = String.fromInt int
                , icon = always Element.none
                }
            )
, onSelect = (\i -> Just <| ChangedSelected i)
}
    |> Widget.multiSelect
    |> Widget.buttonRow
        { elementRow = Material.buttonRow
        , content = Material.toggleButton Material.defaultPalette
        }
    |> always "Ignore this line" --> "Ignore this line"

Modal

Modal


type alias Modal msg =
{ onDismiss : Maybe msg
, content : Element msg 
}

singleModal : List { onDismiss : Maybe msg, content : Element msg } -> List (Element.Attribute msg)

A modal showing a single element.

Material design only allows one element at a time to be viewed as a modal. To make things easier, this widget only views the first element of the list. This way you can see the list as a queue of modals.

import Element

type Msg
    = Close

Element.layout
    (singleModal
        [ { onDismiss = Just Close
          , content =
              Element.text "Click outside this window to close it."
          }
        ]
    )
    |> always "Ignore this line" --> "Ignore this line"

Technical Remark:

multiModal : List { onDismiss : Maybe msg, content : Element msg } -> List (Element.Attribute msg)

Same implementation as singleModal but also displays the "queued" modals.

import Element

type Msg
    = Close

Element.layout
    (multiModal
        [ { onDismiss = Just Close
          , content =
              Element.text "Click outside this window to close it."
          }
        ]
    )
    |> always "Ignore this line" --> "Ignore this line"

Dialog

Dialog


type alias DialogStyle msg =
{ elementColumn : List (Element.Attribute msg)
, content : { title : { contentText : List (Element.Attribute msg) }
, text : { contentText : List (Element.Attribute msg) }
, buttons : { elementRow : List (Element.Attribute msg)
, content : { accept : ButtonStyle msg
, dismiss : ButtonStyle msg } } } 
}


type alias Dialog msg =
{ title : Maybe String
, text : String
, accept : Maybe (TextButton msg)
, dismiss : Maybe (TextButton msg) 
}

Dialog widget type

dialog : DialogStyle msg -> { title : Maybe String, text : String, accept : Maybe (TextButton msg), dismiss : Maybe (TextButton msg) } -> Modal msg

A Dialog Window.

import Widget.Material as Material
import Element

type Msg
    = Submit
    | Close

Element.layout
    (dialog (Material.alertDialog Material.defaultPalette)
        { title = Just "Accept"
        , text = "Are you sure?"
        , accept =
            { text = "Accept"
            , onPress = Just Submit
            }
            |> Just
        , dismiss =
            { text = "Cancel"
            , onPress = Just Close
            }
            |> Just
        }
        |> List.singleton
        |> singleModal
    )
    |> always "Ignore this line" --> "Ignore this line"

List

List

Row


type alias RowStyle msg =
{ elementRow : List (Element.Attribute msg)
, content : { element : List (Element.Attribute msg)
, ifFirst : List (Element.Attribute msg)
, ifLast : List (Element.Attribute msg)
, ifSingleton : List (Element.Attribute msg)
, otherwise : List (Element.Attribute msg) } 
}

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

Replacement of Element.row

import Element
import Widget.Material as Material

[ Element.text "Text 1"
, Element.text "Text 2"
]
    |> Widget.row Material.row
    |> always "Ignore this line" --> "Ignore this line"

buttonRow : { elementRow : RowStyle msg, content : ButtonStyle msg } -> List ( Basics.Bool, Button msg ) -> Element msg

A row of buttons

import Element
import Widget.Material as Material

type Msg =
    Select Int

selected : Maybe Int
selected =
    Just 0

Widget.select
    { selected = selected
    , options =
        [ 1, 2, 42 ]
            |> List.map
                (\int ->
                    { text = String.fromInt int
                    , icon = always Element.none
                    }
                )
    , onSelect = (\i -> Just (Select i ))
    }
    |> Widget.buttonRow
        { elementRow = Material.row
        , content = Material.outlinedButton Material.defaultPalette
        }
    |> always "Ignore this line" --> "Ignore this line"

toggleRow : { elementRow : RowStyle msg, content : ButtonStyle msg } -> List ( Basics.Bool, Button msg ) -> Element msg

A row of icon buttons use this in combination with Material.toggleButton

import Element
import Widget.Material as Material

type Msg =
    Select Int

selected : Maybe Int
selected =
    Just 0

Widget.select
    { selected = selected
    , options =
        [ 1, 2, 42 ]
            |> List.map
                (\int ->
                    { text = String.fromInt int
                    , icon = always Element.none
                    }
                )
    , onSelect = (\i -> Just (Select i ))
    }
    |> Widget.buttonRow
        { elementRow = Material.row
        , content = Material.toggleButton Material.defaultPalette
        }
    |> always "Ignore this line" --> "Ignore this line"

wrappedButtonRow : { elementRow : RowStyle msg, content : ButtonStyle msg } -> List ( Basics.Bool, Button msg ) -> Element msg

A wrapped row of buttons

import Element
import Widget.Material as Material

type Msg =
    Select Int

selected : Maybe Int
selected =
    Just 0

Widget.select
    { selected = selected
    , options =
        [ 1, 2, 42 ]
            |> List.map
                (\int ->
                    { text = String.fromInt int
                    , icon = always Element.none
                    }
                )
    , onSelect = (\i -> Just (Select i ))
    }
    |> Widget.wrappedButtonRow
        { elementRow = Material.row
        , content = Material.outlinedButton Material.defaultPalette
        }
    |> always "Ignore this line" --> "Ignore this line"

Column


type alias ColumnStyle msg =
{ elementColumn : List (Element.Attribute msg)
, content : { element : List (Element.Attribute msg)
, ifFirst : List (Element.Attribute msg)
, ifLast : List (Element.Attribute msg)
, ifSingleton : List (Element.Attribute msg)
, otherwise : List (Element.Attribute msg) } 
}

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

Replacement of Element.column

import Element
import Widget.Material as Material

[ Element.text "Text 1"
, Element.text "Text 2"
]
    |> Widget.column Material.column
    |> always "Ignore this line" --> "Ignore this line"

buttonColumn : { elementColumn : ColumnStyle msg, content : ButtonStyle msg } -> List ( Basics.Bool, Button msg ) -> Element msg

A column of buttons

import Element
import Widget.Material as Material

type Msg =
    Select Int

selected : Maybe Int
selected =
    Just 0

Widget.select
    { selected = selected
    , options =
        [ 1, 2, 42 ]
            |> List.map
                (\int ->
                    { text = String.fromInt int
                    , icon = always Element.none
                    }
                )
    , onSelect = (\i -> Just (Select i ))
    }
    |> Widget.buttonColumn
        { elementColumn = Material.column
        , content = Material.toggleButton Material.defaultPalette
        }
    |> always "Ignore this line" --> "Ignore this line"

Item


type alias ItemStyle content msg =
{ element : List (Element.Attribute msg)
, content : content 
}


type alias Item msg =
List (Element.Attribute msg) -> Element msg

Item widget type.

Use Widget.asItem if you want to turn a simple element into an item.


type alias FullBleedItemStyle msg =
{ elementButton : List (Element.Attribute msg)
, ifDisabled : List (Element.Attribute msg)
, otherwise : List (Element.Attribute msg)
, content : { elementRow : List (Element.Attribute msg)
, content : { text : { elementText : List (Element.Attribute msg) }
, icon : IconStyle } } 
}

fullBleedItem : ItemStyle (FullBleedItemStyle msg) msg -> { text : String, onPress : Maybe msg, icon : Icon msg } -> Item msg

A text item spanning the full width.

import Element
import Widget.Material as Material

[ Widget.fullBleedItem (Material.fullBleedItem Material.defaultPalette)
    { onPress = Nothing
    , icon = always Element.none
    , text = "Item"
    }
, Widget.divider (Material.fullBleedDivider Material.defaultPalette )
, Widget.fullBleedItem (Material.fullBleedItem Material.defaultPalette)
    { onPress = Nothing
    , icon = always Element.none
    , text = "Item"
    }
]
    |> Widget.itemList (Material.cardColumn Material.defaultPalette)
    |> always "Ignore this line" --> "Ignore this line"


type alias InsetItem msg =
{ text : String
, onPress : Maybe msg
, icon : Icon msg
, content : Icon msg 
}


type alias InsetItemStyle msg =
{ elementButton : List (Element.Attribute msg)
, ifDisabled : List (Element.Attribute msg)
, otherwise : List (Element.Attribute msg)
, content : { elementRow : List (Element.Attribute msg)
, content : { text : { elementText : List (Element.Attribute msg) }
, icon : { element : List (Element.Attribute msg)
, content : IconStyle }
, content : IconStyle } } 
}

insetItem : ItemStyle (InsetItemStyle msg) msg -> { text : String, onPress : Maybe msg, icon : Icon msg, content : Icon msg } -> Item msg

A clickable item that contains two spots for icons or additional information and a single line of text.

import Element
import Widget.Material as Material

[ Widget.insetItem (Material.insetItem Material.defaultPalette)
    { onPress = Nothing
    , icon = always Element.none
    , text = "Item"
    , content = always Element.none
    }
, Widget.divider (Material.insetDivider Material.defaultPalette )
, Widget.insetItem (Material.insetItem Material.defaultPalette)
    { onPress = Nothing
    , icon = always Element.none
    , text = "Item"
    , content = always Element.none
    }
]
    |> Widget.itemList (Material.cardColumn Material.defaultPalette)
    |> always "Ignore this line" --> "Ignore this line"


type alias ExpansionItemStyle msg =
{ item : ItemStyle (InsetItemStyle msg) msg
, expandIcon : Icon msg
, collapseIcon : Icon msg 
}


type alias ExpansionItem msg =
{ icon : Icon msg
, text : String
, onToggle : Basics.Bool -> msg
, content : List (Item msg)
, isExpanded : Basics.Bool 
}

expansionItem : ExpansionItemStyle msg -> { icon : Icon msg, text : String, onToggle : Basics.Bool -> msg, content : List (Item msg), isExpanded : Basics.Bool } -> List (Item msg)

An expandable Item

import Element
import Widget.Material as Material

type Msg =
    Toggle Bool

let
    isExpanded : Bool
    isExpanded =
        True
in
(   ( Widget.fullBleedItem (Material.fullBleedItem Material.defaultPalette)
        { onPress = Nothing
        , icon = always Element.none
        , text = "Item with Icon"
        }
    )
    :: Widget.expansionItem (Material.expansionItem Material.defaultPalette )
        { onToggle = Toggle
        , isExpanded = isExpanded
        , icon = always Element.none
        , text = "Expandable Item"
        , content =
            [ Widget.fullBleedItem (Material.fullBleedItem Material.defaultPalette)
            { onPress = Nothing
            , icon = always Element.none
            , text = "Item with Icon"
            }
            ]
        }
)
    |> Widget.itemList (Material.cardColumn Material.defaultPalette)
    |> always "Ignore this line" --> "Ignore this line"


type alias ImageItemStyle msg =
{ elementButton : List (Element.Attribute msg)
, ifDisabled : List (Element.Attribute msg)
, otherwise : List (Element.Attribute msg)
, content : { elementRow : List (Element.Attribute msg)
, content : { text : { elementText : List (Element.Attribute msg) }
, image : { element : List (Element.Attribute msg) }
, content : IconStyle } } 
}


type alias ImageItem msg =
{ text : String
, onPress : Maybe msg
, image : Element msg
, content : Icon msg 
}

imageItem : ItemStyle (ImageItemStyle msg) msg -> { text : String, onPress : Maybe msg, image : Element msg, content : Icon msg } -> Item msg

A clickable item that contains a image , a line of text and some additional information

import Element
import Widget.Material as Material
import Widget.Material.Color as MaterialColor
import Element.Font as Font

[ Widget.imageItem (Material.imageItem Material.defaultPalette)
    { onPress = Nothing
    , image =
        Element.image [ Element.width <| Element.px <| 40, Element.height <| Element.px <| 40 ]
            { src = "https://upload.wikimedia.org/wikipedia/commons/thumb/f/f3/Elm_logo.svg/1024px-Elm_logo.svg.png"
            , description = "Elm logo"
            }
    , text = "Item with Image"
    , content =
        \{ size, color } ->
            "1."
                |> Element.text
                |> Element.el
                    [ Font.color <| MaterialColor.fromColor color
                    , Font.size size
                    ]
    }
]
    |> Widget.itemList (Material.cardColumn Material.defaultPalette)
    |> always "Ignore this line" --> "Ignore this line"


type alias MultiLineItemStyle msg =
{ elementButton : List (Element.Attribute msg)
, ifDisabled : List (Element.Attribute msg)
, otherwise : List (Element.Attribute msg)
, content : { elementRow : List (Element.Attribute msg)
, content : { description : { elementColumn : List (Element.Attribute msg)
, content : { title : { elementText : List (Element.Attribute msg) }
, text : { elementText : List (Element.Attribute msg) } } }
, icon : { element : List (Element.Attribute msg)
, content : IconStyle }
, content : IconStyle } } 
}


type alias MultiLineItem msg =
{ title : String
, text : String
, onPress : Maybe msg
, icon : Icon msg
, content : Icon msg 
}

multiLineItem : ItemStyle (MultiLineItemStyle msg) msg -> { title : String, text : String, onPress : Maybe msg, icon : Icon msg, content : Icon msg } -> Item msg

A item containing a text running over multiple lines.

import Element
import Widget.Material as Material

[ Widget.multiLineItem (Material.multiLineItem Material.defaultPalette)
    { title = "Title"
    , onPress = Nothing
    , icon = always Element.none
    , text = "Item"
    , content = always Element.none
    }
]
    |> Widget.itemList (Material.cardColumn Material.defaultPalette)
    |> always "Ignore this line" --> "Ignore this line"


type alias HeaderStyle msg =
{ elementColumn : List (Element.Attribute msg)
, content : { divider : DividerStyle msg
, title : List (Element.Attribute msg) } 
}

headerItem : ItemStyle (HeaderStyle msg) msg -> String -> Item msg

A header for a part of a list.

import Element
import Widget.Material as Material

[ Widget.fullBleedItem (Material.fullBleedItem Material.defaultPalette)
    { onPress = Nothing
    , icon = always Element.none
    , text = "Item"
    }
, "Header"
    |> Widget.headerItem (Material.insetHeader Material.defaultPalette )
, Widget.fullBleedItem (Material.fullBleedItem Material.defaultPalette)
    { onPress = Nothing
    , icon = always Element.none
    , text = "Item"
    }
]
    |> Widget.itemList (Material.cardColumn Material.defaultPalette)
    |> always "Ignore this line" --> "Ignore this line"


type alias DividerStyle msg =
{ element : List (Element.Attribute msg) }

divider : ItemStyle (DividerStyle msg) msg -> Item msg

A divider.

import Element
import Widget.Material as Material

[ Widget.fullBleedItem (Material.fullBleedItem Material.defaultPalette)
    { onPress = Nothing
    , icon = always Element.none
    , text = "Item"
    }
, Widget.divider (Material.insetDivider Material.defaultPalette )
, Widget.fullBleedItem (Material.fullBleedItem Material.defaultPalette)
    { onPress = Nothing
    , icon = always Element.none
    , text = "Item"
    }
]
    |> Widget.itemList (Material.cardColumn Material.defaultPalette)
    |> always "Ignore this line" --> "Ignore this line"

selectItem : ItemStyle (ButtonStyle msg) msg -> Select msg -> List (Item msg)

Displays a selection of Buttons as a item list. This is intended to be used as a menu.

import Element
import Widget.Material as Material

type Msg =
    Select Int

(   { selected = Just 1
    , options =
        [ "Option 1", "Option 2" ]
            |> List.map
                (\text ->
                    { text = text
                    , icon = always Element.none
                    }
                )
    , onSelect = (\int ->
        int
        |> Select
        |> Just
        )
    }
        |> Widget.selectItem (Material.selectItem Material.defaultPalette)
)
    |> Widget.itemList (Material.cardColumn Material.defaultPalette)
    |> always "Ignore this line" --> "Ignore this line"

asItem : Element msg -> Item msg

Turns a Element into an item. Only use if you want to take care of the styling yourself.

import Element
import Widget.Material as Material

Element.text "Just a text"
    |> Widget.asItem
    |> List.singleton
    |> Widget.itemList (Material.cardColumn Material.defaultPalette)
    |> always "Ignore this line" --> "Ignore this line"

itemList : ColumnStyle msg -> List (Item msg) -> Element msg

Implementation of the Material design list

import Element
import Widget.Material as Material

[ Widget.fullBleedItem (Material.fullBleedItem Material.defaultPalette)
    { onPress = Nothing
    , icon = always Element.none
    , text = "Item"
    }
, "Header"
    |> Widget.headerItem (Material.insetHeader Material.defaultPalette )
, Widget.fullBleedItem (Material.fullBleedItem Material.defaultPalette)
    { onPress = Nothing
    , icon = always Element.none
    , text = "Item"
    }
]
    |> Widget.itemList (Material.cardColumn Material.defaultPalette)
    |> always "Ignore this line" --> "Ignore this line"

App Bar

App Bar


type alias AppBarStyle content msg =
{ elementRow : List (Element.Attribute msg)
, content : { menu : { elementRow : List (Element.Attribute msg)
, content : content }
, search : TextInputStyle msg
, actions : { elementRow : List (Element.Attribute msg)
, content : { button : ButtonStyle msg
, searchIcon : Icon msg
, moreVerticalIcon : Icon msg } } } 
}

menuBar : AppBarStyle { menuIcon : Icon msg, title : List (Element.Attribute msg) } msg -> { title : Element msg, deviceClass : Element.DeviceClass, openLeftSheet : Maybe msg, openRightSheet : Maybe msg, openTopSheet : Maybe msg, primaryActions : List (Button msg), search : Maybe (TextInput msg) } -> Element msg

A app bar with a menu button on the left side.

This should be the default way to display the app bar. Specially for Phone users.

import Element exposing (DeviceClass(..))
import Widget.Material as Material

type Msg =
    Select Int

selected : Int
selected = 0

Widget.menuBar style.tabBar
    { title =
        "Title"
            |> Element.text
            |> Element.el Typography.h6
    , deviceClass = Phone
    , openRightSheet = Nothing
    , openTopSheet = Nothing
    , primaryActions =
        [   { icon =
                Material.Icons.change_history
                    |> Icon.elmMaterialIcons Color
            , text = "Action"
            , onPress = Nothing
            }
        ]
    , search = Nothing
    }

tabBar : AppBarStyle { menuTabButton : ButtonStyle msg, title : List (Element.Attribute msg) } msg -> { title : Element msg, menu : Select msg, deviceClass : Element.DeviceClass, openRightSheet : Maybe msg, openTopSheet : Maybe msg, primaryActions : List (Button msg), search : Maybe (TextInput msg) } -> Element msg

A app bar with tabs instead of a menu.

This is should be used for big screens.

It should be avoided for smaller screens or if you have more then 4 tabs

import Element exposing (DeviceClass(..))
import Widget.Material as Material

type Msg =
    Select Int

selected : Int
selected = 0

Widget.tabBar style.tabBar
    { title =
        "Title"
            |> Element.text
            |> Element.el Typography.h6
    , menu =
        { selected = Just selected
        , options =
            [ "Home", "About" ]
                |> List.map
                    (\string ->
                        { text = string
                        , icon = always Element.none
                        }
                    )
        , onSelect = \int -> int |> Select |> Just
        }
    , deviceClass = Phone
    , openRightSheet = Nothing
    , openTopSheet = Nothing
    , primaryActions =
        [   { icon =
                Material.Icons.change_history
                    |> Icon.elmMaterialIcons Color
            , text = "Action"
            , onPress = Nothing
            }
        ]
    , search = Nothing
    }

Sort Table

Sort Table


type alias SortTableStyle msg =
{ elementTable : List (Element.Attribute msg)
, content : { header : ButtonStyle msg
, ascIcon : Icon msg
, descIcon : Icon msg
, defaultIcon : Icon msg } 
}

Technical Remark:


type alias SortTable a msg =
{ content : List a
, columns : List (Column a)
, sortBy : String
, asc : Basics.Bool
, onChange : String -> msg 
}

Sort Table widget type


type alias Column a =
Internal.SortTable.Column a

Column for the Sort Table widget type

sortTable : SortTableStyle msg -> { content : List a, columns : List (Column a), sortBy : String, asc : Basics.Bool, onChange : String -> msg } -> Element msg

A table where the rows can be sorted by columns

import Widget.Material as Material
import Element

type Msg =
    ChangedSorting String

sortBy : String
sortBy =
    "Id"

asc : Bool
asc =
    True

Widget.sortTable (Material.sortTable Material.defaultPalette)
    { content =
        [ { id = 1, name = "Antonio", rating = 2.456, hash = Nothing }
        , { id = 2, name = "Ana", rating = 1.34, hash = Just "45jf" }
        , { id = 3, name = "Alfred", rating = 4.22, hash = Just "6fs1" }
        , { id = 4, name = "Thomas", rating = 3, hash = Just "k52f" }
        ]
    , columns =
        [ Widget.intColumn
            { title = "Id"
            , value = .id
            , toString = \int -> "#" ++ String.fromInt int
            , width = Element.fill
            }
        , Widget.stringColumn
            { title = "Name"
            , value = .name
            , toString = identity
            , width = Element.fill
            }
        , Widget.floatColumn
            { title = "Rating"
            , value = .rating
            , toString = String.fromFloat
            , width = Element.fill
            }
        , Widget.unsortableColumn
            { title = "Hash"
            , toString = (\{hash} -> hash |> Maybe.withDefault "None")
            , width = Element.fill
            }
        ]
    , asc = asc
    , sortBy = sortBy
    , onChange = ChangedSorting
    }
    |> always "Ignore this line" --> "Ignore this line"

floatColumn : { title : String, value : a -> Basics.Float, toString : Basics.Float -> String, width : Element.Length } -> Column a

A Column containing a Float

intColumn : { title : String, value : a -> Basics.Int, toString : Basics.Int -> String, width : Element.Length } -> Column a

A Column containing a Int

stringColumn : { title : String, value : a -> String, toString : String -> String, width : Element.Length } -> Column a

A Column containing a String

value >> toString field will be used for displaying the content.

value will be used for comparing the content

For example value = String.toLower will make the sorting case-insensitive.

unsortableColumn : { title : String, toString : a -> String, width : Element.Length } -> Column a

An unsortable Column, when trying to sort by this column, nothing will change.

Sort Table V2

Sort Table V2

Like [Sort Table](

Sort Table) but has supports custom elements in columns.


type alias SortTableV2 a msg =
{ content : List a
, columns : List (ColumnV2 a msg)
, sortBy : String
, asc : Basics.Bool
, onChange : String -> msg 
}

Sort Table V2 widget type


type alias ColumnV2 a msg =
Internal.SortTableV2.ColumnV2 a msg

Column for the Sort Table V2 widget type

sortTableV2 : SortTableStyle msg -> { content : List a, columns : List (ColumnV2 a msg), sortBy : String, asc : Basics.Bool, onChange : String -> msg } -> Element msg

A table where the rows can be sorted by columns

import Widget.Material as Material
import Element

type Msg
    = ChangedSorting String
    | PressedButton String

sortBy : String
sortBy =
    "Id"

asc : Bool
asc =
    True

Widget.sortTableV2 (Material.sortTable Material.defaultPalette)
    { content =
        [ { id = 1, name = "Antonio", rating = 2.456, hash = Nothing }
        , { id = 2, name = "Ana", rating = 1.34, hash = Just "45jf" }
        , { id = 3, name = "Alfred", rating = 4.22, hash = Just "6fs1" }
        , { id = 4, name = "Thomas", rating = 3, hash = Just "k52f" }
        ]
    , columns =
        [ Widget.intColumnV2
            { title = "Id"
            , value = .id
            , toString = \int -> "#" ++ String.fromInt int
            , width = Element.fill
            }
        , Widget.stringColumnV2
            { title = "Name"
            , value = .name
            , toString = identity
            , width = Element.fill
            }
        , Widget.floatColumnV2
            { title = "Rating"
            , value = .rating
            , toString = String.fromFloat
            , width = Element.fill
            }
        , Widget.customColumnV2
            { title = "Action"
            , value =
                \{name} ->
                    Widget.textButton
                        (Material.textButton Material.defaultPalette)
                        { text = name
                        , onPress = Just <| PressedButton name
                        }
            , width = Element.fill
            }
        , Widget.unsortableColumnV2
            { title = "Hash"
            , toString = (\{hash} -> hash |> Maybe.withDefault "None")
            , width = Element.fill
            }
        ]
    , asc = asc
    , sortBy = sortBy
    , onChange = ChangedSorting
    }
    |> always "Ignore this line" --> "Ignore this line"

floatColumnV2 : { title : String, value : a -> Basics.Float, toString : Basics.Float -> String, width : Element.Length } -> ColumnV2 a msg

A ColumnV2 containing a Float

intColumnV2 : { title : String, value : a -> Basics.Int, toString : Basics.Int -> String, width : Element.Length } -> ColumnV2 a msg

A ColumnV2 containing a Int

stringColumnV2 : { title : String, value : a -> String, toString : String -> String, width : Element.Length } -> ColumnV2 a msg

A ColumnV2 containing a String

value >> toString field will be used for displaying the content.

value will be used for comparing the content

For example value = String.toLower will make the sorting case-insensitive.

customColumnV2 : { title : String, value : a -> Element msg, width : Element.Length } -> ColumnV2 a msg

A ColumnV2 containing an Element

value will be used for displaying content.

This column is not sortable.

unsortableColumnV2 : { title : String, toString : a -> String, width : Element.Length } -> ColumnV2 a msg

An unsortable ColumnV2, when trying to sort by this column, nothing will change.

Text Input

textInput


type alias TextInputStyle msg =
{ elementRow : List (Element.Attribute msg)
, content : { chips : { elementRow : List (Element.Attribute msg)
, content : ButtonStyle msg }
, text : { elementTextInput : List (Element.Attribute msg) } } 
}


type alias TextInput msg =
{ chips : List (Button msg)
, text : String
, placeholder : Maybe (Element.Input.Placeholder msg)
, label : String
, onChange : String -> msg 
}

Text Input widget type

textInput : TextInputStyle msg -> { chips : List (Button msg), text : String, placeholder : Maybe (Element.Input.Placeholder msg), label : String, onChange : String -> msg } -> Element msg

A text Input that allows to include chips.

import Element
import Widget.Material as Material

type Msg =
    ToggleTextInputChip String
    | SetTextInput String

{text = "Hello World"}
    |> (\model ->
            { chips =
                [ "Cat", "Fish", "Dog"]
                    |> List.map
                        (\string ->
                            { icon = always Element.none
                            , text = string
                            , onPress =
                                string
                                    |> ToggleTextInputChip
                                    |> Just
                            }
                        )
            , text = model.text
            , placeholder = Nothing
            , label = "Chips"
            , onChange = SetTextInput
            }
        )
    |> Widget.textInput (Material.textInput Material.defaultPalette)
    |> always "Ignore this line" --> "Ignore this line"

usernameInput : TextInputStyle msg -> { chips : List (Button msg), text : String, placeholder : Maybe (Element.Input.Placeholder msg), label : String, onChange : String -> msg } -> Element msg

An input field that supports auto filling the username

emailInput : TextInputStyle msg -> { chips : List (Button msg), text : String, placeholder : Maybe (Element.Input.Placeholder msg), label : String, onChange : String -> msg } -> Element msg

An input field that supports auto filling the email

searchInput : TextInputStyle msg -> { chips : List (Button msg), text : String, placeholder : Maybe (Element.Input.Placeholder msg), label : String, onChange : String -> msg } -> Element msg

An input field that supports searching

spellCheckedInput : TextInputStyle msg -> { chips : List (Button msg), text : String, placeholder : Maybe (Element.Input.Placeholder msg), label : String, onChange : String -> msg } -> Element msg

An input field that supports spell checking


type alias PasswordInputStyle msg =
{ elementRow : List (Element.Attribute msg)
, content : { password : { elementPasswordInput : List (Element.Attribute msg) } } 
}


type alias PasswordInput msg =
{ text : String
, placeholder : Maybe (Element.Input.Placeholder msg)
, label : String
, onChange : String -> msg
, show : Basics.Bool 
}

Password Input widget type

newPasswordInputV2 : PasswordInputStyle msg -> { text : String, placeholder : Maybe (Element.Input.Placeholder msg), label : String, onChange : String -> msg, show : Basics.Bool } -> Element msg

An input field that supports auto filling the new password

currentPasswordInputV2 : PasswordInputStyle msg -> { text : String, placeholder : Maybe (Element.Input.Placeholder msg), label : String, onChange : String -> msg, show : Basics.Bool } -> Element msg

An input field that supports auto filling the current password

Tab

tab


type alias TabStyle msg =
{ elementColumn : List (Element.Attribute msg)
, content : { tabs : { elementRow : List (Element.Attribute msg)
, content : ButtonStyle msg }
, content : List (Element.Attribute msg) } 
}


type alias Tab msg =
{ tabs : Select msg
, content : Maybe Basics.Int -> Element msg 
}

Tab widget type

tab : TabStyle msg -> { tabs : Select msg, content : Maybe Basics.Int -> Element msg } -> Element msg

Displays a list of contents in a tab

import Element
import Widget.Material as Material

type Msg =
    ChangedTab Int

selected : Maybe Int
selected =
    Just 0

Widget.tab (Material.tab Material.defaultPalette)
    { tabs =
        { selected = selected
        , options =
            [ 1, 2, 3 ]
                |> List.map
                    (\int ->
                        { text = "Tab " ++ (int |> String.fromInt)
                        , icon = always Element.none
                        }
                    )
        , onSelect =
            (\s ->
                if s >= 0 && s <= 2 then
                    Just (ChangedTab s)
                else
                    Nothing
            )
        }
    , content =
        (\s ->
            case s of
                Just 0 ->
                    "This is Tab 1" |> Element.text
                Just 1 ->
                    "This is the second tab" |> Element.text
                Just 2 ->
                    "The third and last tab" |> Element.text
                _ ->
                    "Please select a tab" |> Element.text
        )
    }
    |> always "Ignore this line" --> "Ignore this line"

Progress Indicator

progress Indicator


type alias ProgressIndicatorStyle msg =
{ elementFunction : Maybe Basics.Float -> Element msg }


type alias ProgressIndicator =
Maybe Basics.Float

Progress Indicator widget type

If maybeProgress is set to Nothing, an indeterminate progress indicator (e.g. spinner) will display. If maybeProgress is set to Just Float (where the Float is proportion of completeness between 0 and 1 inclusive), a determinate progress indicator will visualize the progress.

circularProgressIndicator : ProgressIndicatorStyle msg -> Maybe Basics.Float -> Element msg

Displays a circular progress indicator

import Widget.Material as Material

Just 0.75
|> Widget.circularProgressIndicator (Material.progressIndicator Material.defaultPalette)
|> always "Ignore this line" --> "Ignore this line"

DEPRECATED

newPasswordInput : PasswordInputStyle msg -> PasswordInput msg -> Element msg

An input field that supports auto filling the new password

currentPasswordInput : PasswordInputStyle msg -> PasswordInput msg -> Element msg

An input field that supports auto filling the current password