Orasund/elm-ui-widgets/3.3.0

NOTE: the latest version is 3.4.0

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 (Attribute msg)
, ifDisabled : List (Attribute msg)
, ifActive : List (Attribute msg)
, otherwise : List (Attribute msg)
, content :
{ elementRow : List (Attribute msg)
, content :
{ text : { contentText : List (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

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"
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"
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"

Radio

Radio

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

Radio style type

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

Radio widget type

RadioStyle msg
-> { description : String
, onPress : Maybe msg
, selected : 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 (Attribute msg)
, content :
{ element : List (Attribute msg)
, ifDisabled : List (Attribute msg)
, ifActive : List (Attribute msg)
, otherwise : List (Attribute msg)
}
, contentInFront :
{ element : List (Attribute msg)
, ifDisabled : List (Attribute msg)
, ifActive : List (Attribute msg)
, otherwise : List (Attribute msg)
, content :
{ element : List (Attribute msg)
, ifDisabled : List (Attribute msg)
, ifActive : List (Attribute msg)
, otherwise : List (Attribute msg)
}
}
}
type alias Switch msg =
{ description : String
, onPress : Maybe msg
, active : Bool
}

Switch widget type

SwitchStyle msg
-> { description : String
, onPress : Maybe msg
, active : 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 Int
, options :
List
{ text : String
, icon : Icon msg
}
, onSelect : Int -> Maybe msg
}

Select widget type

Technical Remark:

  • A more suitable name would be "Choice"
selectButton : ButtonStyle msg -> ( 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 ( 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"
toggleButton : ButtonStyle msg -> ( Bool, Button msg ) -> Element msg

A icon button that can be selected. Should be used together with Material.toggleButton

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.toggleRow
        { elementRow = Material.toggleRow
        , content = Material.toggleButton Material.defaultPalette
        }
    |> always "Ignore this line" --> "Ignore this line"

MultiSelect

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

Multi Select widget type

Technical Remark:

  • A more suitable name would be "Options"
multiSelect : MultiSelect msg -> List ( 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

List
{ onDismiss : Maybe msg
, content : Element msg
}
-> List (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:

  • To stop the screen from scrolling, set the height of the layout to the height of the screen.
List
{ onDismiss : Maybe msg
, content : Element msg
}
-> List (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 (Attribute msg)
, content :
{ title : { contentText : List (Attribute msg) }
, text : { contentText : List (Attribute msg) }
, buttons :
{ elementRow : List (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

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 (Attribute msg)
, content :
{ element : List (Attribute msg)
, ifFirst : List (Attribute msg)
, ifLast : List (Attribute msg)
, ifSingleton : List (Attribute msg)
, otherwise : List (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"
{ elementRow : RowStyle msg
, content : ButtonStyle msg
}
-> List ( 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"
{ elementRow : RowStyle msg
, content : ButtonStyle msg
}
-> List ( 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"
{ elementRow : RowStyle msg
, content : ButtonStyle msg
}
-> List ( 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 (Attribute msg)
, content :
{ element : List (Attribute msg)
, ifFirst : List (Attribute msg)
, ifLast : List (Attribute msg)
, ifSingleton : List (Attribute msg)
, otherwise : List (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"
{ elementColumn : ColumnStyle msg
, content : ButtonStyle msg
}
-> List ( 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 (Attribute msg)
, content : content
}
type alias Item msg =
List (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 (Attribute msg)
, ifDisabled : List (Attribute msg)
, otherwise : List (Attribute msg)
, content :
{ elementRow : List (Attribute msg)
, content :
{ text : { elementText : List (Attribute msg) }
, icon : IconStyle
}
}
}
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 (Attribute msg)
, ifDisabled : List (Attribute msg)
, otherwise : List (Attribute msg)
, content :
{ elementRow : List (Attribute msg)
, content :
{ text : { elementText : List (Attribute msg) }
, icon :
{ element : List (Attribute msg)
, content : IconStyle
}
, content : IconStyle
}
}
}
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 : Bool -> msg
, content : List (Item msg)
, isExpanded : Bool
}
ExpansionItemStyle msg
-> { icon : Icon msg
, text : String
, onToggle : Bool -> msg
, content : List (Item msg)
, isExpanded : 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 (Attribute msg)
, ifDisabled : List (Attribute msg)
, otherwise : List (Attribute msg)
, content :
{ elementRow : List (Attribute msg)
, content :
{ text : { elementText : List (Attribute msg) }
, image : { element : List (Attribute msg) }
, content : IconStyle
}
}
}
type alias ImageItem msg =
{ text : String
, onPress : Maybe msg
, image : Element msg
, content : Icon msg
}
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 (Attribute msg)
, ifDisabled : List (Attribute msg)
, otherwise : List (Attribute msg)
, content :
{ elementRow : List (Attribute msg)
, content :
{ description :
{ elementColumn : List (Attribute msg)
, content :
{ title : { elementText : List (Attribute msg) }
, text : { elementText : List (Attribute msg) }
}
}
, icon :
{ element : List (Attribute msg)
, content : IconStyle
}
, content : IconStyle
}
}
}
type alias MultiLineItem msg =
{ title : String
, text : String
, onPress : Maybe msg
, icon : Icon msg
, content : Icon msg
}
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 (Attribute msg)
, content :
{ divider : DividerStyle msg
, title : List (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 (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 (Attribute msg)
, content :
{ menu :
{ elementRow : List (Attribute msg)
, content : content
}
, search : TextInputStyle msg
, actions :
{ elementRow : List (Attribute msg)
, content :
{ button : ButtonStyle msg
, searchIcon : Icon msg
, moreVerticalIcon : Icon msg
}
}
}
}
AppBarStyle
{ menuTabButton : ButtonStyle msg
, title : List (Attribute msg)
}
msg
-> { title : Element msg
, menu : Select msg
, deviceClass : 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 (Attribute msg)
, content :
{ header : ButtonStyle msg
, ascIcon : Icon msg
, descIcon : Icon msg
, defaultIcon : Icon msg
}
}

Technical Remark:

  • If icons are defined in Svg, they might not display correctly. To avoid that, make sure to wrap them in Element.html >> Element.el []
type alias SortTable a msg =
{ content : List a
, columns : List (Column a)
, sortBy : String
, asc : Bool
, onChange : String -> msg
}

Sort Table widget type

type alias Column a =
Column a

Column for the Sort Table widget type

SortTableStyle msg
-> { content : List a
, columns : List (Column a)
, sortBy : String
, asc : 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"
{ title : String
, value : a -> Float
, toString : Float -> String
, width : Length
}
-> Column a

A Column containing a Float

{ title : String
, value : a -> Int
, toString : Int -> String
, width : Length
}
-> Column a

A Column containing a Int

{ title : String
, value : a -> String
, toString : String -> String
, width : 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.

{ title : String
, toString : a -> String
, width : 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 : Bool
, onChange : String -> msg
}

Sort Table V2 widget type

type alias ColumnV2 a msg =
ColumnV2 a msg

Column for the Sort Table V2 widget type

SortTableStyle msg
-> { content : List a
, columns : List (ColumnV2 a msg)
, sortBy : String
, asc : 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"
{ title : String
, value : a -> Float
, toString : Float -> String
, width : Length
}
-> ColumnV2 a msg

A ColumnV2 containing a Float

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

A ColumnV2 containing a Int

{ title : String
, value : a -> String
, toString : String -> String
, width : 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.

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

A ColumnV2 containing an Element

value will be used for displaying content.

This column is not sortable.

{ title : String
, toString : a -> String
, width : 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 (Attribute msg)
, content :
{ chips :
{ elementRow : List (Attribute msg)
, content : ButtonStyle msg
}
, text : { elementTextInput : List (Attribute msg) }
}
}
type alias TextInput msg =
{ chips : List (Button msg)
, text : String
, placeholder : Maybe (Placeholder msg)
, label : String
, onChange : String -> msg
}

Text Input widget type

TextInputStyle msg
-> { chips : List (Button msg)
, text : String
, placeholder : Maybe (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"
TextInputStyle msg
-> { chips : List (Button msg)
, text : String
, placeholder : Maybe (Placeholder msg)
, label : String
, onChange : String -> msg
}
-> Element msg

An input field that supports auto filling the username

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

An input field that supports auto filling the email

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

An input field that supports searching

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

An input field that supports spell checking

type alias PasswordInputStyle msg =
{ elementRow : List (Attribute msg)
, content :
{ password : { elementPasswordInput : List (Attribute msg) } }
}
type alias PasswordInput msg =
{ text : String
, placeholder : Maybe (Placeholder msg)
, label : String
, onChange : String -> msg
, show : Bool
}

Password Input widget type

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

An input field that supports auto filling the new password

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

An input field that supports auto filling the current password

Tab

tab

type alias TabStyle msg =
{ elementColumn : List (Attribute msg)
, content :
{ tabs :
{ elementRow : List (Attribute msg)
, content : ButtonStyle msg
}
, content : List (Attribute msg)
}
}
type alias Tab msg =
{ tabs : Select msg
, content : Maybe Int -> Element msg
}

Tab widget type

tab :
TabStyle msg
-> { tabs : Select msg
, content : Maybe 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 Float -> Element msg }
type alias ProgressIndicator =
Maybe 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 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