kirchner/elm-selectize/2.0.6

NOTE: this package is not compatible with Elm 0.19.1

Selectize

This is a dropdown menu whose entries can be filtered. You can select entries using the mouse or with the keyboard (arrow up/down and enter).

The dropdown menu manages the keyboard and mouse focus, as well as the open/closed state itself. The (unfiltered) list of possible entries and the eventually selected entry have to live in the model of the actual application.

If you want to use it, your model should look something like this

type alias Model =
    { selection : Maybe Tree
    , menu : Selectize.State Tree
    }


type alias Tree =
    { name : String
    , latinName : String
    }

The state of the dropdown menu is instanciated via

menu =
    Selectize.closed "unique-menu-id"
        (\tree -> tree.name ++ " - " ++ tree.latinName)
        (trees |> List.map Selectize.entry)

with

trees : List Tree

And you have to hook it up in your update function like so

type Msg
    = MenuMsg (Selectize.Msg Tree)
    | SelectTree (Maybe Tree)


update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        MenuMsg selectizeMsg ->
            let
                ( newMenu, menuCmd, maybeMsg ) =
                    Selectize.update SelectTree
                        model.selection
                        model.menu
                        selectizeMsg


                newModel =
                    { model | menu = newMenu }


                cmd =
                    menuCmd |> Cmd.map MenuMsg
            in
            case maybeMsg of
                Just nextMsg ->
                    update nextMsg newModel
                        |> andDo cmd


                Nothing ->
                    ( newModel, cmd )


        SelectTree newSelection ->
            ( { model | selection = newSelection }, Cmd.none )


andDo : Cmd msg -> ( model, Cmd msg ) -> ( model, Cmd msg )
andDo cmd ( model, cmds ) =
    ( model
    , Cmd.batch [ cmd, cmds ]
    )

Finally, the menu can be rendered like this

view : Model -> Html Msg
view model =
    Html.div []
        [ Selectize.view viewConfig
            model.selection
            model.menu
            |> Html.map MenuMsg
        ]

with the view configuration given by

viewConfig : Selectize.ViewConfig Tree
viewConfig =
    Selectize.viewConfig
        { container =
            [ Attributes.class "selectize__container" ]
        , menu =
            [ Attributes.class "selectize__menu" ]
        , ul =
            [ Attributes.class "selectize__list" ]
        , entry =
            \tree mouseFocused keyboardFocused ->
                { attributes =
                    [ Attributes.class "selectize__item"
                    , Attributes.classList
                        [ ( "selectize__item--mouse-selected"
                          , mouseFocused
                          )
                        , ( "selectize__item--key-selected"
                          , keyboardFocused
                          )
                        ]
                    ]
                , children =
                    [ Html.text
                        (tree.name ++ " - " ++ tree.latinName)
                    ]
                }
        , divider =
            \title ->
                { attributes =
                    [ Attributes.class "selectize__divider" ]
                , children =
                    [ Html.text title ]
                }
        , input = styledInput
        }

and an input given by, for example,

styledInput : Selectize.Input Tree
styledInput =
    Selectize.autocomplete <|
        { attrs =
            \sthSelected open ->
                [ Attributes.class "selectize__textfield"
                , Attributes.classList
                    [ ( "selectize__textfield--selection", sthSelected )
                    , ( "selectize__textfield--no-selection", not sthSelected )
                    , ( "selectize__textfield--menu-open", open )
                    ]
                ]
        , toggleButton =
            Just <|
                \open ->
                    Html.i
                        [ Attributes.class "material-icons"
                        , Attributes.class "selectize__icon"
                        ]
                        [ if open then
                            Html.text "arrow_drop_up"
                          else
                            Html.text "arrow_drop_down"
                        ]
        , clearButton = Nothing
        , placeholder = "Select a Tree"
        }

Types

type alias State a =
State a

The internal state of the dropdown menu. This lives in your model.

closed : String -> (a -> String) -> List (Entry a) -> State a

Use this function to initialize your dropdown menu, for example by

menu =
    Selectize.closed "unique-menu-id"
        entryToLabel
        entries

It will have the provided entries and be closed. The provided id should be unique. If for some reason the entries change, just reinstantiate your dropdown state with this function.

type alias Entry a =
Entry a

Each entry of the menu has to be wrapped in this type. We need this, as an entry can either be selectable (and therefore also focusable) or not. You can construct these using entry and divider.

entry : a -> Entry a

Create a selectable Entry a.

divider : String -> Entry a

Create a divider, which can neither be selected nor focused. It is therefore skipped while traversing the list via up/down keys.

Update

type alias Msg a =
Msg a

The dropdown menu produces these messages.

(Maybe a -> msg)
-> Maybe a
-> State a
-> Msg a
-> ( State a, Cmd (Msg a), Maybe msg )

The dropdown's update function. Take a look at the beginning of this module documentation to see what boilerplate is needed in your main update.

View

view : ViewConfig a -> Maybe a -> State a -> Html (Msg a)

The dropdown's view function. You have to provide the current selection (along with the configuration and the its actual state).

type alias ViewConfig a =
ViewConfig a

The configuration for Selectize.view.

{ container : List (Attribute Never)
, menu : List (Attribute Never)
, ul : List (Attribute Never)
, entry : a -> Bool -> Bool -> HtmlDetails Never
, divider : String -> HtmlDetails Never
, input : Input a
}
-> ViewConfig a

Create the view configuration, for example

viewConfig : Selectize.ViewConfig String
viewConfig =
    Selectize.viewConfig
        { container = [ ... ]
        , menu = [ ... ]
        , ul = [ ... ]
        , entry =
            \entry mouseFocused keyboardFocused ->
                { attributes = ...
                , children = ...
                }
        , divider =
            \title ->
                { attributes = ...
                , children = ...
                }
        , input = someInput
        }
  • container, menu, ul, entry and divider can be used to style the different parts of the dropdown view, c.f. the modul documentation for an example.
  • with input you can choose if you want autocompletion or just a simple dropdown menu, you can choose for example Selectize.simple or Selectize.autocomplete.
type alias HtmlDetails msg =
{ attributes : List (Attribute msg)
, children : List (Html msg)
}

entry and divider should return this.

type alias Input a =
Input a

You have to choose an Input in your view configuration. This decides if you have a simple dropdown or an autocompletion version.

{ attrs : Bool -> Bool -> List (Attribute Never)
, toggleButton : Maybe (Bool -> Html Never)
, clearButton : Maybe (Html Never)
, placeholder : String
}
-> Input a

An input for displaying a simple dropdown.

  • attrs = \sthSelected open -> [ ... ] is used to style the actual button
  • you can style optional buttons via toggleButton and clearButton, for example toggleButton = Just (\open -> Html.div [ ... ] [ ... ])
  • tell us the placeholder if the selection is empty
{ attrs : Bool -> Bool -> List (Attribute Never)
, toggleButton : Maybe (Bool -> Html Never)
, clearButton : Maybe (Html Never)
, placeholder : String
}
-> Input a

An input for an autocompletion dropdown.

  • attrs = \sthSelected open -> [ ... ] is used to style the actual textfield (You probably need to overwrite the placeholder styling, see the source code of the demo for an example stylesheet.)
  • you can style optional buttons via toggleButton and clearButton, for example toggleButton = Just (\open -> Html.div [ ... ] [ ... ])
  • tell us the placeholder if the selection is empty