Autocomplete InputField

My humble contribution:

(* Use this function to style list elements *)
listItemStyle[item_] := Mouseover[#, Style[#, Background -> LightBlue]] &@ MouseAppearance[Framed[item], "LinkHand"];

(* This filters the list of data and returns a clickable list *)
SetAttributes[autoComplete, HoldFirst];
autoComplete[s_, data_] := If[
  StringLength[s] > 0,
  EventHandler[#, {"MouseClicked" :> (s = #)}] & /@ Select[data, StringMatchQ[#, s ~~ __, IgnoreCase -> True] &],
  {}
  ]

(* Responsible for final output *)
SetAttributes[inputWithAutoComplete, HoldFirst];
inputWithAutoComplete[s_, data_, max_: 5] := Column[{
   InputField[Dynamic[s], String, ContinuousAction -> True],
   Dynamic[listItemStyle /@ (Take[#, Min[Length[#], max]] &@autoComplete[s, data] /. {} -> "") // TableForm]
   }, Left, 1]

Try it using:

data = CountryData[];
s = "";
inputWithAutoComplete[s, data, 10]

dropdown

Version 2.0

I started all over and refactored the code to make it better. There are many advantages so this is definitely the one to use, but I'm not deleting what I posted earlier since the new version is also substantially different, and both may be of interest.

(* Returns expr with styles off or on depending on whether the expr \
is hovered. Additionally the cursor as the mouse if hovering the \
expression can be set. *)

MouseoverStyled[expr_, off_, on_, cursor_: "LinkHand"] := Deploy[
  MouseAppearance[Mouseover[
    Style[expr, off],
    Style[expr, on]
    ], cursor]
  ]

(* Returns a list item with the given text *)

item[text_] := MouseoverStyled[Framed[text], {}, {Background -> LightBlue}]

(* Create a list of clickable items *)

items[labels_, func_] := EventHandler[
     item[#], {
      "MouseClicked" :> func[#]
      }
     ] & /@ labels;

(* Picks out the n first elements that start with input *)

filter[input_, data_, n_: 10] := Take[#, Min[Length[#], n]] &@Select[data, StringMatchQ[#, input ~~ __, IgnoreCase -> True] &]

(* Final presentation *)

inputWithAutoomplete[data_] := DynamicModule[{s = ""},
  Column[{
    InputField[Dynamic[s], String, ContinuousAction -> True],
    Dynamic@If[StringLength[s] > 0, Column[items[filter[s, data], (s = #) &]], ""]
    }]]

Test it like this:

inputWithAutoomplete[Last /@ CountryData[]]

or with just CountryData[] for more countries, but I noticed this can be quite slow (it didn't use to be - but since V10 with the EntityValue thing.)


I also took a crack at this. I think I made it look pretty close to the jquery example you posted. Figuring out how to move the insertion point to the end of the word once a suggestion is selected was a bit of a struggle. As a result, there's a DynamicWrapper in there that may be unstable.

Input is the list of possible values from which you'd like to draw suggestions.

Enjoy!

autocompleteInputField[possibilities:{_String..}]:=DynamicModule[{nb,ind=0,txt,suggestions,suggestedElements,returnKeyTrigger=False},

suggestions = Dynamic[
                If[Length[suggestedElements] < 1 || StringLength[txt] <= 1,
                    "",
                (* else *)
                    Column[
                        MapIndexed[
                            Button[
                                Function[panel,Mouseover[Style[panel,Background->If[ind===First[#2],LightBlue,White]],Style[panel,Background->LightBlue]]]@Pane[#1,ImageMargins->0],
                                (
                                    txt=#1;
                                    returnKeyTrigger=True
                                ),
                                Appearance->"Frameless"
                            ]&,
                            If[!(If[Length[suggestedElements]===1,First[suggestedElements]===txt,False]) && StringLength[txt]>1,
                                suggestedElements,
                                {}
                            ]
                        ],
                        Background->White,
                        Frame->True
                    ]
                ]
            ];
Column[{
    DynamicWrapper[
        EventHandler[
            InputField[
                Dynamic[txt],
                String,
                ContinuousAction->True,
                BaseStyle->{FontFamily->"Arial"}
            ],
            {
                "DownArrowKeyDown":>(ind=Min[ind+1,Length[suggestedElements]]),
                "UpArrowKeyDown":>(ind=Max[0,ind-1]),
                "ReturnKeyDown":>
                    If[Length[suggestedElements]>0 && ind>0,
                        txt=suggestedElements[[ind]];
                        ind=0;
                        returnKeyTrigger=True
                    ]
            }
        ],
        If[returnKeyTrigger,
            returnKeyTrigger=False;
            SelectionMove[nb,Next,Word]
        ],
        SynchronousUpdating->False
    ],
    suggestions
}],

Initialization:>(
    nb = EvaluationNotebook[];
    txt="";
    suggestedElements:=Pick[possibilities,StringMatchQ[possibilities,txt~~__]]
    )

]

Maybe overkill but it was educational to try:

DynamicModule[{},
 EventHandler[
  Overlay[{
          Dynamic@Framed[
             Row[{Style[x, Transparent, 15, Bold], Style[rest, [email protected], 15, Bold]}],
              ImageSize -> {280, 30}, Alignment -> Top, FrameMargins -> {{5, 0}, {0, 1}}],
          InputField[Dynamic@x, String, BaseStyle -> {Bold, Black, 15}, Alignment -> Top,
                     ContinuousAction -> True, ImageSize -> {280, 30}, FrameMargins -> 0]

          }, {2, 1}, 2]
         , {"ReturnKeyDown" :> (x = x ~~ rest), 
            "UpArrowKeyDown" :> (names = RotateLeft@names), 
            "DownArrowKeyDown" :> (names = RotateRight@names)}
             ]
 , Initialization :> (x = "";
     names := Names["System`" ~~ x ~~ "*"]; 
     rest := If[Length@names == 0 \[Or] x == "", "", 
                StringDrop[First[names], 
                Clip[StringLength@x, {0, StringLength@First[names]}]]]
                     )
 ]

Mathematica graphics

Please forgive me but I have no time to make it more user friendly.

There is no menu, only auto filling which you accept with Enter or you can also switch between fillings with arrows.

I have a couple of ideas, I'm going to write them tomorrow.