jaredramirez / elm-select / Select

Select items from a menu list.

Set up


type State


type alias MenuItem item =
{ item : item, label : String }

The menu item that will be represented in the menu list.

The item property is the type representation of the menu item that will be used in an Action.

The label is the text representation that will be shown in the menu.

type Tool
    = Screwdriver
    | Hammer
    | Drill

toolItems : MenuItem Tool
toolItems =
    [ { item = Screwdriver, label = "Screwdriver" }
    , { item = Hammer, label = "Hammer" }
    , { item = Drill, label = "Drill" }
    ]

yourView model =
    Html.map SelectMsg <|
        view
            (single Nothing
                |> menuItems toolItems
                |> state model.selectState
            )
            (selectIdentifier "SingleSelectExample")


type Action item
    = InputChange String
    | Select item
    | DeselectMulti item
    | ClearSingleSelectItem

Specific events happen in the Select that you can react to from your update.

Maybe you want to find out what country someone is from?

When they select a country from the menu, it will be reflected in the Select action.

import Select exposing ( Action(..) )

type Msg
    = SelectMsg (Select.Msg Country)
    -- your other Msg's

type Country
    = Australia
    | Japan
    | Taiwan
    -- other countries

update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
    case msg of
        SelectMsg selectMsg ->
            let
                (maybeAction, selectState, selectCmds) =
                    Select.update selectMsg model.selectState

                selectedCountry : Maybe Country
                selectedCountry =
                    case maybeAction of
                        Just (Select.Select someCountry) ->
                            Just someCountry

                        Nothing ->
                            Nothing

            in
            -- (model, cmd)

initState : State

Set up an initial state in your init function.

type Country
    = Australia
    | Japan
    | Taiwan

type alias Model =
    { selectState : Select.State
    , items : List (Select.MenuItem Country)
    , selectedCountry : Maybe Country
    }

init : Model
init =
    { selectState = Select.initState
    , items =
        [ { item = Australia, label = "Australia" }
        , { item = Japan, label = "Japan" }
        , { item = Taiwan, label = "Taiwan" }
        ]
    , selectedCountry = Nothing
    }


type Msg item

menuItems : List (MenuItem item) -> Config item -> Config item

The items that will appear in the menu list.

NOTE: When using the (multi) select, selected items will be reflected as a tags and visually removed from the menu list.

  items =
      [ { item = SomeValue, label = "Some label" } ]

  yourView =
      view
          (Single Nothing |> menuItems items)
          (selectIdentifier "1234")

placeholder : String -> Config item -> Config item

The text that will appear as an input placeholder.

    yourView model =
        Html.map SelectMsg <|
            view
                (single Nothing |> placeholder "some placeholder")
                (selectIdentifier "1234")

selectIdentifier : String -> SelectId

The ID for the rendered Select input

NOTE: It is important that the ID's of all selects that exist on a page remain unique.

yourView model =
    Html.map SelectMsg <|
        view
            (single Nothing)
            (selectIdentifier "someUniqueId")

state : State -> Config item -> Config item

    model : Model
    model =
        { selectState = initState }

    yourView : Model
    yourView model =
        Html.map SelectMsg <|
            view
                (single Nothing |> state model.selectState)
                (selectIdentifier "1234")

update : Msg item -> State -> ( Maybe (Action item), State, Platform.Cmd.Cmd (Msg item) )

Add a branch in your update to handle the view Msg's.

    yourUpdate msg model =
        case msg of
            SelectMsg selectMsg ->
                update selectMsg model.selectState

view : Config item -> SelectId -> Html.Styled.Html (Msg item)

Render the select

    yourView model =
        Html.map SelectMsg <|
            view
                (single Nothing)
                (selectIdentifier "SingleSelectExample")

searchable : Basics.Bool -> Config item -> Config item

Renders an input that let's you input text to search for menu items.

    yourView model =
        Html.map SelectMsg <|
            view
                (single Nothing |> searchable True)
                (selectIdentifier "1234")

NOTE: This doesn't affect the Native single select variant.

setStyles : Styles.Config -> Config item -> Config item

Change some of the visual styles of the select.

Useful for styling the select using your color branding.

    import Select.Styles as Styles

    branding : Styles.Config
    branding =
        Styles.controlDefault
            |> Styles.setControlBorderColor (Css.hex "#FFFFFF")
            |> Styles.setControlBorderColorFocus (Css.hex "#0168B3")
            |> Styles.setControlStyles Styles.default

    yourView model =
        Html.map SelectMsg <|
            view
                (single Nothing |> setStyles branding)
                (selectIdentifier "1234")

Single select

single : Maybe (MenuItem item) -> Config item

Select a single item.

  countries : List (MenuItem Country)
  countries =
      [ { item = Australia, label = "Australia" }
      , { item = Taiwan, label = "Taiwan"
      -- other countries
      ]

  yourView =
      Html.map SelectMsg <|
          view
              (single Nothing |> menuItems countries)
              (selectIdentifier "1234")

clearable : Basics.Bool -> Config item -> Config item

Allows a single variant selected menu item to be cleared.

To handle a cleared item refer to the ClearedSingleSelect action.

    yourView model =
        Html.map SelectMsg <|
            view
                ( single Nothing
                    |> clearable True
                    |> menuItems -- [ menu items ]
                )
                (selectIdentifier "SingleSelectExample")

Multi select

multi : MultiSelectConfig -> List (MenuItem item) -> Config item

Select multiple items.

Selected items will render as tags and be visually removed from the menu list.

yourView model =
    Html.map SelectMsg <|
        view
            (multi
                (initMultiConfig
                    |> menuItems model.countries
                )
                model.selectedCountries
            )
            (selectIdentifier "1234")

truncateMultiTag : Basics.Float -> MultiSelectConfig -> MultiSelectConfig

Limit the width of a multi select tag.

Handy for when the selected item text is excessively long. Text that breaches the set width will display as an ellipses.

Width will be in px values.

    yourView model =
        Html.map SelectMsg <|
            view
                (multi
                    ( initMultiConfig
                        |> truncateMultitag 30
                    )
                    model.selectedCountries
                )
                (selectIdentifier "1234")

multiTagColor : Css.Color -> MultiSelectConfig -> MultiSelectConfig

Set the color for the multi select tag.

    yourView =
        Html.map SelectMsg <|
            view
                (multi
                    ( initMultiConfig
                        |> multiTagColor (Css.hex "#E1E2EA"
                    )
                    model.selectedCountries
                )
                (selectIdentifier "1234")

initMultiConfig : MultiSelectConfig

Starting value for the 'multi' variant.

    yourView model =
        Html.map SelectMsg <|
            view
                (multi initMultiConfig [])
                (selectIdentifier "1234")

Native Single select

singleNative : Maybe (MenuItem item) -> Config item

Select a single item with a native html select element.

Useful for when you want to give a native select experience such as on touch devices.

  countries : List (MenuItem Country)
  countries =
      [ { item = Australia, label = "Australia" }
      , { item = Taiwan, label = "Taiwan"
      -- other countries
      ]

  yourView =
      Html.map SelectMsg <|
          view
              (singleNative Nothing |> menuItems countries)
              (selectIdentifier "1234")

Note

Common

disabled : Basics.Bool -> Config item -> Config item

Disables the select input so that it cannot be interacted with.

    yourView model =
        Html.map SelectMsg <|
            view
                (single Nothing |> disabled True)
                (selectIdentifier "SingleSelectExample")

labelledBy : String -> Config item -> Config item

The element ID of the label for the select.

It is best practice to render the select with a label.

yourView model =
    label
        [ id "selectLabelId" ]
        [ text "Select your country"
        , Html.map SelectMsg <|
            view
                (single Nothing |> labelledBy "selectLabelId")
                (selectIdentifier "SingleSelectExample")
        ]

ariaDescribedBy : String -> Config item -> Config item

The ID of element that describes the select.

yourView model =
    label
        [ id "selectLabelId" ]
        [ text "Select your country"
        , Html.map SelectMsg <|
            view
                (single Nothing
                    |> labelledBy "selectLabelId"
                    |> ariaDescribedBy "selectDescriptionId"
                )
                (selectIdentifier "SingleSelectExample")
        , div [ id "selectDescriptionId" ] [ text "This text describes the select" ]
        ]

loading : Basics.Bool -> Config item -> Config item

Displays an animated loading icon to visually represent that menu items are being loaded.

This would be useful if you are loading menu options asynchronously, like from a server.

    yourView model =
        Html.map SelectMsg <|
            view
                (single Nothing |> loading True)
                (selectIdentifier "SingleSelectExample")

Advanced

jsOptimize : Basics.Bool -> State -> State

Opt in to a Javascript optimization.

Read the Advanced section of the README for a good explanation on why you might like to opt in.

    model : Model model =
        { selectState = initState |> jsOptimize True }

Install the Javascript package:

npm

npm install @confidenceman02/elm-select

Import script

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Viewer</title>

    <script src="/node_modules/@confidenceman02/elm-select/dist/dynamic.min.js"></script>
  </head>
  <body>
    <main></main>
    <script src="index.js"></script>
  </body>
</html>

Alternatively you can import the script wherever you are initialising your program.

import { Elm } from "./src/Main";
import "@confidenceman02/elm-select"

Elm.Main.init({node, flags})