In Windows Sharepoint Service sites a special drop down menu is used for context menus of document library items. You can reuse the javascript code for your own drop down menus. One example for such a drop down menu is a custom 'create new document' combobox which lets you choose a template for the new document from a list of registered document templates. (In SharePoint you can select only one template per document library which is not very useful in practice)

Here is what you have to do for it.

  1. Create a webpart that renders a hidden table with all elements for your new 'magicmagic' combobox. The webpart registers the javascript for displaying the combobox a la SharePoint

  2. public MyWebPart()
    {
        this.PreRender += new EventHandler(PreRenderScript);
    }

    private void PreRenderScript(object sender , System.EventArgs e)
    {
        if(!Page.IsClientScriptBlockRegistered("MYSPDDScript"))
        {
            Page.RegisterClientScriptBlock("MYSPDDScript", "<script language=""javascript"" src=""/_layouts/1031/t-myspdd.js""></script>");
        }
    }

    protected override void RenderWebPart(HtmlTextWriter output)
    {
        output.RenderBeginTag(HtmlTextWriterTag.Table);
        output.RenderBeginTag(HtmlTextWriterTag.Tr);
        output.RenderBeginTag(HtmlTextWriterTag.Td);

        foreach(Item contextMenuItem in Items)
            // add your data for the context menu item instead of ... !
            output.Write("<a name=\"MyData\" ... />\n");

        output.RenderEndTag();
        output.RenderEndTag();
        output.RenderEndTag();
    }


  3. Add a combobox to the xml file of a site and register mouse events wich call the onMyItem-Method of your registered Javascript code (step 1). The xml will look something like this.

  4. <!-- MyButton -->
    <td class="ms-toolbar" id="]]></HTML><GetVar Name="WPQ"/><HTML><![CDATA[buttonMy">
      <table cellpadding=1 cellspacing=0 border=0>
        <tr>
          <td class="ms-toolbar" nowrap>
            <img src="/_layouts/images/newdoc.gif" ID="tbbutton1N" alt=]]></HTML><HTML>"MyDropdown"</HTML><HTML><![CDATA[ border=0 width=16 height=16>
          </td>
          <td nowrap>
            <table class="ms-unselectedtitle" onmouseover="OnMyItem(this, ']]></HTML><GetVar Name="MyParameter"/><HTML><![CDATA[')" CTXName="ctx1" ItemId="1" >
              <tr>
                <td class="ms-vb" nowrap>MySomething</td>
                <td><img src="/_layouts/images/blank.gif" width=13 style="visibility: hidden" alt=""></td>
              </tr>
            </table>
          </td>
        </tr>
      </table>
    </td>

  5. Write your own javascript with the help of the sharepoint javascript for displaying the drop down menu. The code reads the table items (created by the webpart in step 1) and fills the object structures for the Sharepoint methods with it.

  6. // triggered by onmouseover
    // creates the contexmenu similar to OnItem in ows.js
    function OnMyItem(elm, libUrl)
    {
        if(IsMenuOn())
        {
            StartDeferItem(elm);
            return false;
        }

        if (itemTable != null)
            OutItem();

        itemTable = elm;
        currentItemID = itemTable.ItemId;
        var createCtx = new Function("setupMyMenuContext(" + itemTable.CTXName + ");");
        createCtx();
        var ctx = currentCtx;

        itemTable.className="ms-selectedtitle";
        itemTable.onclick = CreateMyMenu;
        itemTable.oncontextmenu = CreateMyMenu;
        itemTable.onmouseout = OutItem;
        itemTable.libUrl = libUrl;

        titleRow = itemTable.children[0].children[0];

        i = 0;
        while (titleRow.children[i] != null)
            imageCell = titleRow.children[i++];

        downArrowText = "MyCombo";

        imageCell.children[0].src = ctx.imagesPath + "downarrw.gif";
        imageCell.children[0].alt = downArrowText;
        imageCell.children[0].style.visibility = "visible";
        imageCell.style.visibility="visible";
        imageCell.className="ms-menuimagecell";

        return true;
    }

    function setupMyMenuContext(ctx)
    {
        currentCtx = ctx;
    }

    // creates the contextmenu-object similar to CreateMenu in ows.js
    function CreateMyMenu()
    {
        if (! IsContextSet())
            return;
        var ctx = currentCtx;
        if (itemTable == null || imageCell == null ||
            (onKeyPress == false &&
             (event.srcElement.tagName=="A" ||
              event.srcElement.parentNode.tagName == "A")))
            return;
        IsMenuShown = true;
        window.document.body.onclick="";
        m = CMenu(currentItemID + "_menu");
        currenMenu = m;
        AddMyMenuItems(m, itemTable.libUrl, ctx);
        OMenu(m, itemTable, null, null, -1);
        document.body.onclick=HideSelectedRow;
        return false;
    }


    // adds the menu entries for every a-element rendered in RenderWebPart
    function AddMyMenuItems(m, libUrl, ctx)
    {
        setupMenuContext(ctx);

        if(document.getElementsByName("MyDat") != null)
        {
            for(i = 0; i < document.getElementsByName("MyDat").length; i++)
            {
                var myData = document.getElementsByName("MyData")[i];

                var optionEntry = document.createElement("option");

                strTitle     = ""; // add your menu item text here (i.e. myData.Title)
                strAction    = ""; // add your menu item selection action here
                                   // i.e. call createNewDocumentWithProgID to launch an office app with a new document
                strImagePath = ""; // add the path to the menu item icon here

                // CAMSep(m); // adds a separator in the menu item list

                // add the next item to the drop down menu
                mi = CAMOpt(m, strTitle, strAction, strImagePath);
            }
        }
    }


The code is a little bit cumbersome but works in the current versions of Sharepoint Portal Server and Windows Sharepoint Services. As the previous code relies heavily on the internal script structure of SharePoint it can not be guaranteed, that this method will work in the next versions.