EdutainmentLIVE / elm-bootstrap / Bootstrap.Dropdown

Dropdowns are toggleable, contextual overlays for displaying lists of links and more. They’re toggled by clicking, not by hovering; this is an intentional design decision.

Wiring needed

import Bootstrap.Button as Button
import Bootstrap.Dropdown as Dropdown


-- .. etc
-- Model
type alias Model =
    { myDrop1State : Dropdown.State
    , myDrop1State : Dropdown.State
    }


-- Msg
type Msg
    = MyDrop1Msg Dropdown.State
    | MyDrop2Msg Dropdown.State


-- init
init : ( Model, Cmd Msg )
init =
    ( { myDrop1State = Dropdown.initialState
      , myDrop2State = Dropdown.initialState
      }
    , Cmd.none
    )


-- update
update : Msg -> Model -> ( Model, Cmd msg )
update msg model =
    case msg of
        MyDrop1Msg state ->
            ( { model | myDrop1State = state }
            , Cmd.none
            )

        MyDrop2Msg state ->
            ( { model | myDrop2State = state }
            , Cmd.none
            )


-- ... and cases for the drop down actions
subscriptions : Model -> Sub Msg
subscriptions model =
    Sub.batch
        [ Dropdown.subscriptions model.myDrop1State MyDrop1Msg
        , Dropdown.subscriptions model.myDrop2State MyDrop2Msg
        ]

view : Model -> Html Msg
view model =
    div []
        [ Dropdown.dropdown
            model.myDrop1State
            { options = [ Dropdown.alignMenuRight ]
            , toggleMsg = MyDrop1Msg
            , toggleButton =
                Dropdown.toggle [ Button.roleWarning ] [ text "MyDropdown1" ]
            , items =
                [ Dropdown.buttonItem [ onClick Item1Msg ] [ text "Item 1" ]
                , Dropdown.buttonItem [ onClick Item2Msg ] [ text "Item 2" ]
                , Dropdown.divider
                , Dropdown.header [ text "Silly items" ]
                , Dropdown.buttonItem [ class "disabled" ] [ text "DoNothing1" ]
                , Dropdown.buttonItem [] [ text "DoNothing2" ]
                ]
            }

        -- etc
        ]

Bootstrap dropdowns are made interactive in Elm by using state and subscription, so there is a little bit of wiring involved when using them in your Elm Application.

Dropdown

dropdown : State -> { toggleMsg : State -> msg, toggleButton : DropdownToggle msg, options : List (DropdownOption msg), items : List (DropdownItem msg) } -> Html msg

Creates a Dropdown button. You can think of this as the view function. It takes the current (view) state and a configuration record as parameters.

Dropdown.dropdown
    model.myDropdownState
    { toggleMsg = MyDropdownMsg
    , toggleButton = Dropdown.toggle [ Button.primary ] [ text "MyDropdown" ]
    , options = [ Dropdown.alignMenuRight ]
    , items =
        [ Dropdown.buttonItem [ onClick Item1Msg ] [ text "Item1" ]
        , Dropdown.buttonItem [ onClick Item2Msg ] [ text "Item1" ]
        ]
    }

toggle : List (Bootstrap.Button.Option msg) -> List (Html msg) -> DropdownToggle msg

Function to construct a toggle for a dropdown


type DropdownToggle msg

Opaque type representing a toggle button item for a Dropdown

Options

dropUp : DropdownOption msg

Option to show the dropdown menu above the dropdown rather than the default which is below

dropLeft : DropdownOption msg

Show menu to the left of the button.

dropRight : DropdownOption msg

Show menu to the right of the button.

alignMenuRight : DropdownOption msg

Option to align the dropdown menu to the right of the dropdown button.

NOTE! Dropdowns are positioned only with CSS and may need some additional styles for exact alignment.

attrs : List (Html.Attribute msg) -> DropdownOption msg

Use this function when you need the customize the Dropdown root div with additional Html.Attribute (s).

menuAttrs : List (Html.Attribute msg) -> DropdownOption msg

Use this function when you need the customize the Dropdown menu with additional Html.Attribute (s).


type DropdownOption msg

Opaque type representing configuration options for a Dropdown

Dropdown items

anchorItem : List (Html.Attribute msg) -> List (Html msg) -> DropdownItem msg

Creates an a element appropriate for use in dropdowns

buttonItem : List (Html.Attribute msg) -> List (Html msg) -> DropdownItem msg

Creates a button element appropriate for use in dropdowns

divider : DropdownItem msg

Creates divider element appropriate for use in dropdowns. Handy when you want to visually separate groups of menu items in a dropdown menu

header : List (Html msg) -> DropdownItem msg

Creates an header element appropriate for use in dropdowns. Handy when you want to provide a heading for a group of menu items in a dropdown menu

customItem : Html msg -> DropdownItem msg

Creates a dropdown item from any html element


type DropdownItem msg

Opaque type representing an item in the menu of a Dropdown

Split dropdown

splitDropdown : State -> { toggleMsg : State -> msg, toggleButton : SplitDropdownToggle msg, options : List (DropdownOption msg), items : List (DropdownItem msg) } -> Html msg

Creates a split dropdown. Contains a normal button and a toggle button that are placed next to each other.

splitToggle : SplitToggleConfig msg -> SplitDropdownToggle msg

Function to construct a split button toggle for a splitDropdown

Dropdown.splitToggle
    { options =
        [ Button.primary
        , Button.small
        , Button.attr <| onClick SplitMainMsg
        ]
    -- It makes sense to keep the styling related options in sync for the two buttons !
    , togglerOptions =
        [ Button.primary
        , Button.small
        ]
    , [ text "My Dropdown"]
    }


type alias SplitToggleConfig msg =
{ options : List (Bootstrap.Button.Option msg)
, togglerOptions : List (Bootstrap.Button.Option msg)
, children : List (Html msg) 
}

The configuration options available for the toggle in a Split Dropdown.

Important You mustn't define an onClick handler as an option in options. That will mess up the toggle feature !


type SplitDropdownToggle msg

Opaque type representing a split toggle button item for a Split Dropdown

Required wiring

subscriptions : State -> (State -> msg) -> Platform.Sub.Sub msg

The dropdowns makes use of subscriptions to ensure that opened dropdowns are automatically closed when you click outside them.

subscriptions : Model -> Sub Msg
subscriptions model =
    Sub.batch
        [ Dropdown.subscriptions model.myDrop1State MyDrop1Msg
        , Dropdown.subscriptions model.myDrop2State MyDrop2Msg

        -- etc one for each dropdown (dropdown, navDropdown or splitDropdown)
        ]

initialState : State

Initializes the view state for a dropdown. Typically you would call this from your main init function


type State

Opaque type representing the view state of a Dropdown. You need to store this state in your model and it's initialized by initialState