This is a talk page for improving Toggle.

Please leave the latest message at the top.

Nice recipe, I like it very much. I thought of adding a new option disable=hide (or disable=show) to disable hiding (or showing, resp.) the target element with the link/button. For example, disable=hide could turn a group of togglers into radio buttons: once pushed, the button cannot be released, unless another button of the same group is pressed. For that I would store the new option's value ("hide" or "show") in the JavaScript array window.toggleData, check in the JavaScript function toggleObj() if T.new_state_to_toggle_to is equal to the disabled action, and if not then continue with toggling the target.

I have also found some bugs:

  • Unassigned variables $error_opening_tag and $error_closing_tag in line 283 of toggle.php version 2022-06-17. The 'use' PHP language construct should be used (or an arrow function as of PHP 7.4?).
  • (:toggleset ...:) ineffectively stores settings in array element $ToggleConfigStack[''] if $MarkupMarkupLevel is null in line 142 of toggle.php version 2022-06-17. Shouldn't it be $ToggleConfigStack[$MarkupMarkupLevel ?? 0] instead?

If button=1 then ttshow and tthide don't seem to work. It would be good if they worked on a hover over the button simon August 24, 2021, at 05:43 AM

This is now fixed. —Said Achmiz November 18, 2021, at 06:59 AM

This was discussed beginning late October, 2017. See HansB's note on this page immediately before yours. Somewhere in your config files ($FarmD/local/farmconfig.php, local/config.php, local/TTC.php), the site is loading the Page Table Of Contents recipe (pagetoc.php or some older version).

The solution is to download and install the current versionΔ of pagetoc.php and follow the instruction of the first item under "Some usage notes in relation to other scripts" on the Page Table Of Contents page.
ChuckG July 13, 2018, at 01:27 AM

There is a conflict with PageTableOfContents version 20150814 and earlier. It can partly be avoided by including the toggle.php script before including the pagetoc.php script, until such time the PageTOC recipe is updated to avoid using the same name for its own toggle markup. HansB November 03, 2017, at 02:58 AM

This line:

 $HTMLFooterFmt[] = "<script type=\"text/javascript\">document.getElementById(\"{$id}\").style.display = '{$style}';</script>";

causes a JavaScript error — Uncaught TypeError: Cannot read property 'style' of null — when this recipe is used with HandyTableOfContents (I'm guessing this is because it's run prior to HandyTOC having inserted the ToC element?).

Said Achmiz August 22, 2017, at 09:14 AM
UPDATE: It seems like the above line can be replaced by the following:
$HTMLFooterFmt[] = "<script type=\"text/javascript\">if(element = document.getElementById(\"{$id}\")) { = '{$style}'; }</script>";
This seems to solve the error.
Said Achmiz August 22, 2017, at 10:05 AM

Note: This fix is now incorporated into the recipe. Said Achmiz August 24, 2017, at 04:43 PM

Denning Services, , 20160202-12:35GMT-06
I attempted to encapsulate and utilize the toggle directive within and as a Section Header label.
It does use the CSS web-font kit class but cannot seem to change color either CSS or in-line.

'''This example works, but is in Grey and not the defined #660000 or #4e0e19:

!![-(:toggle id=FontLinks01 init=hide button=0 hide="Hide Web-Fonts" show="Installed Web-Font Kits" :) -]
>>id=FontLinks01 border='1px solid #999' padding=2px bgcolor=<< 

I have tried editing the Local CSS, Skin CSS, inspected the Web-Font Kit CSS, and Toggle PHP definitions. Something eluded me.
These examples do not work: (Please note that line breaks are for display purposes only. ).

!!%color=#660000%[-(:toggle id=FontLinks01 init=hide button=0 hide="Hide Web-Fonts" show="Installed Web-Font Kits" :) -]%%
!![-%color=#660000%(:toggle id=FontLinks01 init=hide button=0 hide="Hide Web-Fonts" show="Installed Web-Font Kits" :)%% -]
!![-(:toggle id=FontLinks01 init=hide button=0 
  hide=%color=#660000%"Hide Web-Fonts"%% 
  show=%color=#660000%"Installed Web-Font Kits"%% :) -]
!![-(:toggle id=FontLinks01 init=hide button=0 
  hide="%color=#660000%Hide Web-Fonts%%" 
  show="%color=#660000%Installed Web-Font Kits%%" :) -]

!![-(:toggle id=FontLinks01 init=hide button=0 
  hide="(:html:) <span class=shalomnormal1> Hide Web-Fonts </span> (:htmlend:)" 
  show="(:html:) <span class=shalomnormal1> Installed Web-Font Kits </span> (:htmlend:)" :) -]
!![-(:toggle id=FontLinks01 init=hide button=0 
  hide="(:html:) <span color=#660000> Hide Web-Fonts </span> (:htmlend:)" 
  show="(:html:) <span color=#660000>Installed Web-Font Kits </span> (:htmlend:)" :) -]

At least this one shows the color
!![- (:html:) <span color=#660000 > (:toggle id=FontLinks01 init=hide button=0 
  hide="Hide Installed Web-Font Kits" 
  show="Installed Web-Font Kits" :) </span> (:htmlend:) -]



!![-(:toggle id=FontLinks01 init=hide button=0 
  hide="(:html:) <span class=shalomnormal1 color=#660000 > Hide Web-Fonts </span> (:htmlend:)" 
  show="(:html:) <span class=shalomnormal1 color=#660000 > Installed Web-Font Kits </span> (:htmlend:)" :) -]

The secret? Use a span with class AND color (no quotes) with Cookbook:EnableHTML.
Now, using the Toggle directive in conjunction with in-line HTML,
I can override the H2 header class and stylize my font even as a section header label!

SteP 2015-12-23 bug fix version attached

I fixed the wrong label bug that I reported on 2015-12-18. Download fixed toggle.phpΔ. Consider this file an interim version until Hans can take a look.

SteP 2015-12-18 renders wrong label

(:toggle hide s1 label="Kunst und Kultur" group=info-main-5:) | \
(:toggle hide s2 label="Wein und Essen" group=info-main-5:)

>>id="s1" class="info-main-5 toggler"<<
!!!! Kunst und Kultur
>>id="s2" class="info-main-5 toggler"<<
!!!! Wein und Essen

correctly renders as

Kunst und Kultur | Wein und Essen
on page load, but incorrectly renders as
Wein und Essen | Wein und Essen

after clicking the "Wein und Essen" link.

SteP 2015-12-18 js error on other div's group= partial match

If group=info is used and the page includes an unrelated div.other-info the js script will attempt to toggle div.other-info and trigger a js error in so doing. The intended is left untriggered. Work-around: use a unique class name for the group= parameter.

Is it possible to make toggle display the show and hide text inline?

e.g. some text (:toggle show='more' ...:)
simon October 22, 2015, at 02:33 AM

Great recipe! One little thing I don't understand: Is there a reason why in Notes you suggest to hide the initial div by defining "hide" as a general class? Doesn't this work more simply?:

(:toggle abc init=hide:)
>>id=abc comment<<
hidden content...

You can use the comment wikistyle with equal effect, as it makes the div invisible. So you are right, there is no need to define the css class 'hide'! - HansB February 02, 2014, at 06:21 PM

Are any of you incredible scriptors (of course Hans B. is tops as the writer of the script) up to including a way to link a password script to the toggle recipe in the cookbook and/or config pages. Any password script, such as Zubrag's or PhpBuddy, would do. Just think what a boon it would be to be able to hide stuff in plain site. I've tried, but am missing somewhere.

The script can be split into at least two, toggle1 and toggle2. I've succeeded at that, but not at more. Just search for "toggle," change it to toggle 1, and then change the script name. Of course, the id in the usage script must match, as well. Thank you! Humbly yours, Jagtig

A wonder recipe! And, did you know that font-family markup is compatible. For example:

Toggle, font-family, etc
(:toggle hide boxq21q51433 button:)
>>id=boxq21q51433 border='3px solid #f63' font-family=Georgia color=orange font-size=18pt padding=12px width=300px bgcolor=#000000<<
This is your text.

This is your text.

I wonder if there is a way to toggle between more than 2 ids? Not nesting, just rotating through more than 2. Thanks for the fun recipe!

Maria 2013.06.26

I know I could do this under the old SHOWHIDE system. I am trying to nest toggles within toggles. In this example one toggle reveals two other toggles which in-turn have info inside. Alas... it doesn't work. For me the last toggle is always outside what should be the master toggle. Is nesting possible? Am I doing it wrong?. Here's my example code:

(:toggle id=aaa init=hide show="Toggle everything!" hide="Toggle everything!":)

(:toggle id=aabb init=hide show="Toggle AABB" hide="Toggle AABB":)
some AABB text here!

(:toggle id=bbbb init=hide show="Toggle BBBB" hide="Toggle BBBB":)
some BBBB text here!

NelsonIngersoll 2011.12.21

The wiki style sections >>....<< do not nest. Use div directives with special index. See DivisionsExplained. - HansB December 22, 2011, at 03:17 AM

I'm having problems getting the code produced by Toggle to validate as XHTML 1.0 Strict. The problem seems to be with the following statement in the PHP file (line 169):

    $out .= '<script type="text/javascript">document.write("<a class=\'togglelink\' title=\''.$tooltip.'\' href=\"'.$act.'\">'.$label.'</a>")</script> ';

Something doesn't seem to be correct about the nesting of the apostrophes and quotes and/or the document.write call isn't properly stripping out the backslashes around the href attribute.

I'm not fully sure that I understand why this needs to be wrapped up in a javascript block in the first place. What would be wrong with swapping out the original line for this one (which validates correctly, per the W3C site):

    $out .= '<a class=\'togglelink\' title=\''.$tooltip.'\' href="'.$act.'">'.$label.'</a>';

Thanks for your help and for the useful recipe! - svoida November 7, 2011 @ 1:42pm PST

I wish the old (:showhide ...:) mark up still worked. It's kind of hard to use this if it's going to break all of my pages that currently use showhide. Is there an easy way to add an alias so I can update my wiki pages at leisure? erh 2011/09/07 at 12:34PM

Try this: add to config.php:

Markup('showhide', 'directives',
  "ToggleMarkup(\$pagename, PSS('$1'))");

This should be sufficient. The old parameters lshow and lhide and the div and div2 will still be recognised by the toggle script, even though the preferred new ones are instead show and hide and id and id2. - HansB September 07, 2011, at 12:25 PM

Is there a way to turn off the new feature that shows all toggled divs when javascript is not enabled? Previously my slow-loading pages loaded smoothly, but now the normally hidden sections appear while the page is loading, which is very jarring. While I can see the virtue of the new behavior, the old behavior works much better for websites that load slowly and that require javascript. Another note: my toggle links provide important information, serving as a sort of header for the content that is revealed. If they disappear when javascript is disabled, that information will be gone. RandyB April 01, 2011, at 10:49 PM

I've now added a switch option: nojs=1 or nojs=2 for this. I think nojs=2 will achieve what you are asking. Please test and let me know if this option is sufficient! It is not a full revert to the old code, as that added inline styles, and I wanted to move away from these. - HansB April 03, 2011, at 02:53 AM

I tested nojs=2 on a couple of pages. This version works much better than the last when no cookie is involved - no more jarring visuals while loading. But I've encountered a problem involving my sidebar and cookies. When I use set=1 to make a cookie control the initial state, the toggle initially works correctly as long as the toggle is on the page. But when the toggle is in the sidebar, it shows the sidebar's div even when my last page view left it hidden. The sidebar's toggles are presented with the correct show or hide text - it's just that their divs are shown regardless. However, when I'm viewing the sidebar page itself, the toggles work correctly both in the sidebar and on the page. - RandyB April 03, 2011, at 10:51 AM

Thanks for checking this out! I remember the problem, and that's why I introduced inline <style> tags for hiding divs, but these are apparently breaking validation. So to give an option for more fluid page loading with hidden divs nojs=2 puts the style in the header. Except that toggle markup in a sidebar or other sub-page cannot do that (and I forgot). Can not using nojs=2 for sidebar toggles be a solution for you, say by setting in the toggle nojs=1 or nojs=0 if nojs=2 is your default? Another way would be to back-introduce the inline style tags, say with a switch nojs=3. But you see it is starting to get rather complex! HansB

I'm not sure what you mean by "setting in the toggle nojs=1 or nojs=0 if nojs=2 is your default" I tried changing the sidebar's toggles to nojs=0 and nojs=1, but neither helped. As I understand what you said, there is no way to prevent the temporary display of the hidden div when it's in the sidebar. If there is no solution, I'll probably have to remove all toggles from my sidebar and other sub-pages. That would be a shame, because they provide a great deal of functionality. For example, in my sidebar is a menu that the user customizes on the fly, showing the parts that are currently of interest, with those parts persisting from one page to the next until the user's interests change. But if the choice is between getting pages to validate and jarring the users, I'd rather have pages that do less but do it correctly and render cleanly. - RandyB April 03, 2011, at 02:34 PM

I've discovered another functional problem when the toggle control is not on the main page - it's a bigger problem than just a temporary flashing of a hidden div. When I load a page with the toggle's status set by cookie to hide, clicking the toggle doesn't appear to have any effect. However, clicking it actually did have an effect (presumably because it succeeded in setting the cookie), because when I reload the page, the change now appears. When the toggle starts with the div shown, however, it works as expected. Basically it appears toggle doesn't work correctly on a subpage. - RandyB April 03, 2011, at 10:54 PM

Please check out latest release which addresses this subpage bug. - HansB April 04, 2011, at 07:06 AM

In the sidebar, the toggle shows the div when first loaded even when the toggle is in its "hide" state. When I click on it to show and then click again to hide, it finally hides the div. - RandyB April 04, 2011, at 10:50 AM

I uploaded the file again. Version 2011-04-04. Please try once more. HansB

This version appears to fix the big functional problem that I cited, in my quick test. While it still briefly does that jarring display of the hidden div in the sidebar (I'm using nojs=2 and set=1), it does end up with the toggle and the div both in the proper state. - RandyB April 04, 2011, at 08:20 PM

Oh good. Here is an idea how to get rid of the brief show of sidebar or other subpage-toggled div when it is initially supposed to be hidden: put a class of 'hide' to your initially hidden div, in addition to your normal toggle setting. Define 'hide' in local.css for instance as

.hide {display:none;}
(:toggle abc init=hide:)
>>id=abc hide<<

HansB April 05, 2011, at 02:34 AM

This didn't have any effect in my wiki. Maybe it's because it's not fresh-out-of-the-box pmwiki. Is local.css automatically included, or does the skin have to do something to include it? Also, is the local.css file supposed to be in pub/ or in pub/css/ ? - RandyB April 05, 2011, at 01:18 PM

Create a file local.css in folder pub/css/ if there is none. PmWiki icludes it automatically for all pages. You can check the HTML source of your page, its in the <head> section. Of course you could include the .hide definition in your skin's css file. Note the dot before hide, it is essential! And make sure you force a refresh from the server, with Windows you press Ctrl plus F5, or hold down the Shift key and click the Refresh button.
Or add to config.php:

$HTMLStylesFmt[] = " .hide {display:none;}";

you can even put display=none directly as style into your div markup, without a .hide style class:

(:toggle abc init=hide:)
>>id=abc display=none<<

HansB April 05, 2011, at 02:58 PM

Thanks for the suggestion. I tried the >>id=abc display=none<< method, but the result was that in the initial view of the page the div was always hidden - even in the "show" state. Now it will only show if I toggle the link to hide and then back to show. I've tried it both with nojs=2 and omitting nojs. - RandyB April 05, 2011, at 08:37 PM

Latest version 2011-04-06 may solve this. You can explicitly hide both first and second div, using one of the methods I explained above. The js will show div according to toggle state (cookie induced or not). HansB

That ALMOST works! When I define the div using (:div1 etc.:) instead of >>div1 etc.<<, it shows the hidden div. Other than that though, it seems to work so far. Just for other's info: javascript needs time to do its magic, so on slow loading pages users may see a shown div appear late in the page loading process, just like images can appear late during page loading. But, with that one exception, the toggle itself will now be correct from the start, and a hidden div (which contains the spoiler perhaps) never appears when it shouldn't. - RandyB April 06, 2011, at 10:30 PM

A syntax error perhaps? You need to set id=divname (same in both markups). display=none does not work with (:div1 etc.:). Use style= or class= in the markup:

(:div id=abc style="display:none" class=hide:)

HansB April 07, 2011, at 01:12 AM

Yes, that was the problem. Thanks so much, Hans! - RandyB April 07, 2011, at 03:56 AM

Is it possible to make all the toggled items visible (or hidden) with one click?
Toggle has now a group=<classname> option, which will hide all divs with class <classname>, but show the associated one. This does not go as far as you like perhaps, but is a step into acting on multiple divs. - HansB

Is it possible to run in the toggle text with the previous line (which might be a section head)?
I don't know what you mean by run in. - HansB

Thanks/ WRF 21 March 2011

The latest toggle recipe produces invalid html code since it adds inline <style ...>-tags. Strangly, validates. It seems that doesn't use the donwload-able version. I have uploaded a patched version which uses the $HTMLStylesFmt variable to add styles instead of adding inline <style ...>-tags (toggle-2010-12-06.phpΔ). JL December 05, 2010, at 06:03 PM

Fixed in latest release. In addition toggle is now non-javascript friendly, meaning it will not show any toggle links or buttons when javascript is disabled/not present, and will show all divs which may otherwise have been hidden. - HansB March 31, 2011, at 02:58 AM

SteP 26 November 2010: There is an undocumented argument to set tooltips for image toggles, use ttshow= and tthide=. I think that the tooltips need to use &nbsp; instead of spaces, and avoid using double quotes (JavaScript gets in the way?)

What a wonderful thing! Toggle makes all my wikis much more usable.

but do not start an id with a number

* '''3D Tools''' \
(:toggle hide tdt:)
(:div1010040109 id=tdt:)
  • [show] / [hide] doesn't have to be FIRST, as shown above, it shows up as

3D Tools [Show]

  • I originally had the id as 3dt (3d tools) and when shown, even though I said hide, the section
    was shown. Just as a wild guess, I tried a non-numeric (or at least non-numeric leading character id
    and that worked!
  • Note the use of the backslash character alone on a line - this makes a neat way to invisibly insert blank lines in your source to help separate sections. Makes it a tiny bit more WYSIWYG
  • P.S. maybe obvious to all, but alpha "divs" didn't work I use a date/time for example, to make them unique.

Ward Christensen October 17, 2010, at 08:45 AM

I'm having the same intention as simon (toggling several entities together). As there is a javascript function document.getElementsByName() probably we could use this instead of getElementsById? We then eventually could name all those elements the same instead of "classing" them.

thank you Markus August 23, 2010, at 13:39

Is it possible to specify hidden divs are not to be printed on an individual div or page basis?

thanks simon August 16, 2010, at 09:42 PM

I would find it useful to allow id2 to be a list. And perhaps id1 as well.

as always thanks for an excellent recipe, simon July 18, 2010, at 02:14 AM

I have a number of entities in a page that I want to toggle at the same time. All have the same class. As both class and id can be used as a selector (see [1] or [2] for example) is it possible to add a class parameter to toggle

thanks simon May 19, 2010, at 06:13 AM

Sounds like a good idea. But not so easy to write. I try when I get some time and inspiration, but I find javascript difficult to write. - HansB May 20, 2010, at 07:22 AM

Just want to say how much I appreciate the backwards compatibility of the recipe on a large wiki. simon November 24, 2009, at 04:31 PM

Is it possible to toggle by a checkbox and not with just a normal button?
I need the state of a checkbox and want to toggle more detailed information if its true. Is it possible with this cookbook?

thanks dboi? October 29, 2009, at 13:00 PM

How to default to display if JavaScript is turned off?

If a visitor has JavaScript turned off (say, with a paranoid implementation of NoScript that doesn't have this wiki yet whitelisted) the default state of the toggle-div cannot be changed. Which is intuitive, since JavaScript changes the toggle. But, if the default state is hidden. then the toggle-text can never be revealed. This is not so hot from an unobtrusive javascript persepctive, much less a user perspective.

The toggle-left/toggle-right implementations in the triad-skin skin, for instance, degrades gracefully with JavaScript turned off -- potentially hidden elements are revealed, via the following usage:

<script type='text/javascript' ><!--
if (toggleLeft) 
document.write("<input name='lb' type='button' 
class='togglebox' value='Hide &darr;' 
onclick='toggleLeft()' />") 

So, if we try adding the following to the end oftoggle.php (prior to return Keep($out); :

// suppress toggle if JavaScript not enabled
$out = "<script type='text/javascript' ><!--
\n if (true) document.write(\"" . $ addslashes($out) . "\" )\n

We get toggle-boxes when JavaScript is enabled, and the hidden text when it is not.

HOWEVER -- this may not always be what the user wants... say, if an "answer" is hidden by default... how to handle these sort of cases? Have a config variable like $toggleDegradeGracefully = 1; by default?

OtherMichael September 13, 2009, at 12:21 PM

I have gif files stored under the pub/bullet directory. How can I set the path in the show parameter ? SH

Toggle can only handle images attached to a page, like show=Site/show.png, but not files in some pub directory. The path gets evaluated by using variable $UploadUrlFmt, which points to the uploads directory, or per page subdirectory. I recommend uploading the images to a page in the Site group and using the above syntax for the toggle markup in other pages. - HansB August 11, 2009, at 09:24 AM

I am having a problem. When I mix buttons and images, only links show even when I have button=1. For example, I use these arguments: show="Table of Contents" hide=hidebtn.gif button=1 but "Table of Contents" becomes a link, instead of a button.

That is correct. If one of show= or hide= labels is set as an image, the toggle becomes a link, and button=1 will be ignored. Toggle will not set images to buttons (which are form elements and require more complicated HTML syntax for image buttons), nor does it allow to have a form button for "Show" and a link (or image link) for "Hide", you can't mix button and link/image. - HansB

I'm having an odd issue when using toggle in sidebars.[3]
The initial setting does not appear to be honoured when it is set to hide, and the "set=1" parameter appears to be ignored in the sidebar. I'm wondering the the cookie handling has changed in some way when related to the sidebar?

thanks simon July 21, 2009, at 11:00 PM test

Fixed now in latest release. Thanks for pointing this out! - HansB July 23, 2009, at 03:40 AM

thanks for the brilliantly quick fix. Would you expect in my test case for there to be an issue where toggle directive is in both the sidebar and the main page? simon July 24, 2009, at 04:35 AM
there should be no issues having several toggle directives, just make sure the div acted on in the sidebar has a different id than a div acted on in the main page content. (i can't connect to your server [Page Load Error], so I can't check your test page) - HansB

Is it possible to use it for headings and toggle show/hide entire sections without having to explicitly add the IDs and toggle markup on each page and on each heading? Utopiah

no, you need to explicitly set a ID in each markup. Perhaps the UnToggle recipe can serve you better? HansB

Is $EnablePrintHiddenDivs supported by Toggle?
Use $ToggleConfig['printhidden'] = false; The $ToggleConfig array uses the same parameters as the markup for its keywords. 'printhidden' is by default true (hidden objects get printed). You can see the other array elements in the script at the beginning of the ToggleMarkup function.

Also, why not use class, rather than id, to identify objects, this would mean one could have several parts of a page toggled by the same button

simon June 21, 2009, at 04:28 PM

And thanks for this recipe and your work on it, I find it invaluable.
I don't see how this could work. We need element IDs for the javascript, so the visible or hidden style can be assigned to it. - HansB

ah, I didb't appreciate the implementation details, assumed that a class and an id could be treated similarly, simon July 21, 2009, at 11:00 PM

Great idea to combine togglelink and showhide. Note that apostrophe still doesn't work on my Mac. (Same problem as I described for togglelink.) -- RandyB

I enabled the recipe but had to remove a second show-hide link for the markup produced by it to validate. --Petko March 08, 2009, at 06:44 PM

Thanks! I can see the validation problem if there is more than one toggle for the same object, as they will carry same id's. The javascript needs the id of the surrounding span tag in order to write the toggle link or form as dynamic content into it. So I don't see a way to fix this restriction on validation. Of course several toggle objects each with one toggle link or button cause no problems, as each object and toggle have unique id's. - HansB

I just want to mention (since i've run into this problem both times implementing this fantastic script) to ensure that your skin/template you're using has a <!--HTMLFooter--> tag towards the bottom. This is needed to load the javascript (and the old version of blix and newspaper skin i'm using neither had that tag).

Thanks again for the great work!

Talk page for the Toggle recipe (users).