├── LICENSE ├── README.md ├── index.bs └── index.html /LICENSE: -------------------------------------------------------------------------------- 1 | Creative Commons Legal Code 2 | 3 | CC0 1.0 Universal 4 | 5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN 7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS 10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM 11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED 12 | HEREUNDER. 13 | 14 | Statement of Purpose 15 | 16 | The laws of most jurisdictions throughout the world automatically confer 17 | exclusive Copyright and Related Rights (defined below) upon the creator 18 | and subsequent owner(s) (each and all, an "owner") of an original work of 19 | authorship and/or a database (each, a "Work"). 20 | 21 | Certain owners wish to permanently relinquish those rights to a Work for 22 | the purpose of contributing to a commons of creative, cultural and 23 | scientific works ("Commons") that the public can reliably and without fear 24 | of later claims of infringement build upon, modify, incorporate in other 25 | works, reuse and redistribute as freely as possible in any form whatsoever 26 | and for any purposes, including without limitation commercial purposes. 27 | These owners may contribute to the Commons to promote the ideal of a free 28 | culture and the further production of creative, cultural and scientific 29 | works, or to gain reputation or greater distribution for their Work in 30 | part through the use and efforts of others. 31 | 32 | For these and/or other purposes and motivations, and without any 33 | expectation of additional consideration or compensation, the person 34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she 35 | is an owner of Copyright and Related Rights in the Work, voluntarily 36 | elects to apply CC0 to the Work and publicly distribute the Work under its 37 | terms, with knowledge of his or her Copyright and Related Rights in the 38 | Work and the meaning and intended legal effect of CC0 on those rights. 39 | 40 | 1. Copyright and Related Rights. A Work made available under CC0 may be 41 | protected by copyright and related or neighboring rights ("Copyright and 42 | Related Rights"). Copyright and Related Rights include, but are not 43 | limited to, the following: 44 | 45 | i. the right to reproduce, adapt, distribute, perform, display, 46 | communicate, and translate a Work; 47 | ii. moral rights retained by the original author(s) and/or performer(s); 48 | iii. publicity and privacy rights pertaining to a person's image or 49 | likeness depicted in a Work; 50 | iv. rights protecting against unfair competition in regards to a Work, 51 | subject to the limitations in paragraph 4(a), below; 52 | v. rights protecting the extraction, dissemination, use and reuse of data 53 | in a Work; 54 | vi. database rights (such as those arising under Directive 96/9/EC of the 55 | European Parliament and of the Council of 11 March 1996 on the legal 56 | protection of databases, and under any national implementation 57 | thereof, including any amended or successor version of such 58 | directive); and 59 | vii. other similar, equivalent or corresponding rights throughout the 60 | world based on applicable law or treaty, and any national 61 | implementations thereof. 62 | 63 | 2. Waiver. To the greatest extent permitted by, but not in contravention 64 | of, applicable law, Affirmer hereby overtly, fully, permanently, 65 | irrevocably and unconditionally waives, abandons, and surrenders all of 66 | Affirmer's Copyright and Related Rights and associated claims and causes 67 | of action, whether now known or unknown (including existing as well as 68 | future claims and causes of action), in the Work (i) in all territories 69 | worldwide, (ii) for the maximum duration provided by applicable law or 70 | treaty (including future time extensions), (iii) in any current or future 71 | medium and for any number of copies, and (iv) for any purpose whatsoever, 72 | including without limitation commercial, advertising or promotional 73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each 74 | member of the public at large and to the detriment of Affirmer's heirs and 75 | successors, fully intending that such Waiver shall not be subject to 76 | revocation, rescission, cancellation, termination, or any other legal or 77 | equitable action to disrupt the quiet enjoyment of the Work by the public 78 | as contemplated by Affirmer's express Statement of Purpose. 79 | 80 | 3. Public License Fallback. Should any part of the Waiver for any reason 81 | be judged legally invalid or ineffective under applicable law, then the 82 | Waiver shall be preserved to the maximum extent permitted taking into 83 | account Affirmer's express Statement of Purpose. In addition, to the 84 | extent the Waiver is so judged Affirmer hereby grants to each affected 85 | person a royalty-free, non transferable, non sublicensable, non exclusive, 86 | irrevocable and unconditional license to exercise Affirmer's Copyright and 87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the 88 | maximum duration provided by applicable law or treaty (including future 89 | time extensions), (iii) in any current or future medium and for any number 90 | of copies, and (iv) for any purpose whatsoever, including without 91 | limitation commercial, advertising or promotional purposes (the 92 | "License"). The License shall be deemed effective as of the date CC0 was 93 | applied by Affirmer to the Work. Should any part of the License for any 94 | reason be judged legally invalid or ineffective under applicable law, such 95 | partial invalidity or ineffectiveness shall not invalidate the remainder 96 | of the License, and in such case Affirmer hereby affirms that he or she 97 | will not (i) exercise any of his or her remaining Copyright and Related 98 | Rights in the Work or (ii) assert any associated claims and causes of 99 | action with respect to the Work, in either case contrary to Affirmer's 100 | express Statement of Purpose. 101 | 102 | 4. Limitations and Disclaimers. 103 | 104 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 105 | surrendered, licensed or otherwise affected by this document. 106 | b. Affirmer offers the Work as-is and makes no representations or 107 | warranties of any kind concerning the Work, express, implied, 108 | statutory or otherwise, including without limitation warranties of 109 | title, merchantability, fitness for a particular purpose, non 110 | infringement, or the absence of latent or other defects, accuracy, or 111 | the present or absence of errors, whether or not discoverable, all to 112 | the greatest extent permissible under applicable law. 113 | c. Affirmer disclaims responsibility for clearing rights of other persons 114 | that may apply to the Work or any use thereof, including without 115 | limitation any person's Copyright and Related Rights in the Work. 116 | Further, Affirmer disclaims responsibility for obtaining any necessary 117 | consents, permissions or other rights required for any use of the 118 | Work. 119 | d. Affirmer understands and acknowledges that Creative Commons is not a 120 | party to this document and has no duty or obligation with respect to 121 | this CC0 or use of the Work. 122 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # css-toggle 2 | Proposal for a CSS Toggle spec 3 | -------------------------------------------------------------------------------- /index.bs: -------------------------------------------------------------------------------- 1 |
   2 | Title: CSS Toggles
   3 | Group: CSSWG
   4 | Status: UD
   5 | Work Status: exploring
   6 | ED: http://tabatkins.github.io/css-toggle/
   7 | Shortname: css-toggle
   8 | Level: 1
   9 | Editor: Tab Atkins Jr., Google, http://xanthir.com/contact
  10 | Editor: Miriam E. Suzanne, Invited Expert, http://miriamsuzanne.com/contact
  11 | Abstract: This specification defines a way to associate a "toggleable value" with an element which can be used in Selectors to select an element, and declarative ways to set and modify this value on the element.
  12 | Ignored Terms: spoiler-text
  13 | Warning: custom
  14 | Custom Warning Title: Abandoned
  15 | Custom Warning Text: This spec attempted to handle too many things at once; the distinct behaviors may have an underlying mechanic driving them, but end up needing very different interaction/accessibility behaviors to be usable in practice. Instead, multiple more targeted proposals (`
` groups, carousel styling, etc) are being pursued. 16 |
17 | 18 | 22 | 23 | 40 | 41 |

42 | Introduction

43 | 44 | This section is not normative. 45 | 46 | Many user-interface languages define elements which can have "toggleable state", 47 | which can be modified by user interaction 48 | and responded to by the element. 49 | For example, in HTML, the <input type=checkbox> has a "checked" state 50 | which toggles between true and false when the user activates the element, 51 | and which is selected by the '':checked'' pseudoclass. 52 | 53 | These sorts of elements are extremely useful, 54 | to the point that authors sometimes abuse them 55 | to get the same functionality on other elements: 56 | 57 |
58 | The following markup example shows how to lightly abuse HTML semantics 59 | to declaratively use toggleable state: 60 | 61 | 62 | <ul class='ingredients'> 63 | <li><label><input type=checkbox><span>1 banana</span></label> 64 | <li><label><input type=checkbox><span>1 cup blueberries</span></label> 65 | ... 66 | </ul> 67 | <style> 68 | input[type='checkbox'] { 69 | display: none; 70 | } 71 | input[type='checkbox']:checked + span { 72 | color: silver; 73 | text-decoration: line-through; 74 | } 75 | </style> 76 | 77 | 78 | In this markup, 79 | one can cross out ingredients as they're used in the recipe 80 | by simply clicking on them, 81 | without any scripting being involved. 82 | The <{label}> "transfers" the activation 83 | to the (hidden) checkboxes, 84 | which are then used to style the span. 85 |
86 | 87 | This module generalizes this ability 88 | and allows it to be applied to any element via CSS, 89 | so authors do not have to abuse host language semantics for styling purposes. 90 | It defines a a way of attaching lightweight "state" to an element via CSS 91 | ('toggle-root'), 92 | defining how user interactions can change that state 93 | ('toggle-trigger'), 94 | and responding to that state from CSS 95 | ('':toggle()'' pseudo-class). 96 | Scripting can also create, modify, and respond to this state, 97 | to accommodate more complicated scenarios. 98 | 99 | It also defines how to infer reasonable accessibility semantics 100 | from the toggle structure, 101 | making it simpler and more reliable 102 | to produce accessible pages 103 | using these sorts of basic interactivity 104 | without the author having to manually annotate a page 105 | with ARIA attributes or similar. 106 | 107 |

108 | Terminology

109 | 110 | Any element can become a toggle root, 111 | meaning it hosts one or more [=toggles=]. 112 | Each [=toggle=] has a name, 113 | a value between 0 and some maximum, 114 | and a few other bits of metadata, 115 | all of which can be set via the 'toggle-root' property. 116 | The toggle is visible to the [=toggle root=], 117 | its descendants, 118 | and possibly its siblings and their descendants 119 | (if the toggle says they can); 120 | any element that can "see" a [=toggle=] 121 | can use the '':toggle()'' pseudo-class 122 | to select the element based on the toggle's value. 123 | 124 | Any element that can see a [=toggle=] 125 | can also trigger the toggle, 126 | changing its value when the element is "activated", 127 | via the 'toggle-trigger' property. 128 | This means you can have elements that self-trigger their own toggle, 129 | like checkboxes, 130 | but also have toggles that are visible to wide sections of a page 131 | and are triggered by buttons (or tabs, or headings, etc) 132 | inside that section, 133 | so multiple elements can use '':toggle()'' to respond to the toggle. 134 | 135 | Toggles can also be grouped together, 136 | so that only one of the toggles in the group 137 | can have a non-zero value at a time, 138 | like how radio buttons work in HTML. 139 | 140 | 141 |

142 | Toggle Concepts

143 | 144 | A toggle is a [=struct=] associated with an [=element=], 145 | which represents something that can be toggled on or off by user action, 146 | and matched with Selectors. 147 | Toggles have the following [=struct/items=]: 148 | 149 |
150 | : name 151 | :: A <>. 152 | 153 | : value 154 | :: 155 | A <> or non-negative <>: 156 | either 0 (the inactive value) 157 | or a value 1 or higher (the active values). 158 | 159 | 160 | : states 161 | :: 162 | Either an integer greater than or equal to 1, 163 | indicating the nominally maximum integer [=toggle/value=], 164 | or a [=/list=] of unique state names, 165 | each of which are <>s. 166 | 167 | This also defines the maximum state of a toggle, 168 | as either the [=toggle/states=] value (if it's an integer) 169 | or the length of [=toggle/states=] minus 1 (if it's a list). 170 | 171 | Note: Toggles can be set to integer values larger than than the "maximum", 172 | or to ident values not given in the list of names, 173 | but when a toggle is incremented or decremented 174 | it will treat all such values as out-of-bounds 175 | and bring the value back within the range defined by [=toggle/states=]. 176 | 177 | : group 178 | :: 179 | A [=boolean=] indicating whether the [=toggle=] is part of a [=toggle group=] 180 | (of the same [=toggle/name=]) 181 | or not. 182 | 183 | : scope 184 | :: 185 | An enum indicating what sort of [=toggle/scope=] the [=toggle=] uses. 186 | It can have two values: 187 | 188 | * "wide", indicating the toggle has [=toggle/wide scope=] 189 | (it's visible to the element, its descendants, 190 | and its following siblings and their descendants). 191 | * "narrow", indicating the toggle has [=toggle/narrow scope=] 192 | (it's visible to the element and its descendants only). 193 | 194 | : overflow 195 | :: An enum 196 | (either "cycle", "cycle-on" or "sticky"), 197 | specifying how to react when a [=toggle activation=] 198 | would increment the [=toggle/value=] 199 | above its maximum 200 | or below its minimum. 201 | 202 |
203 | The precise details are defined in [=change a toggle=], 204 | but in short: 205 | 206 | * For ''cycle'', 207 | incrementing past the maximum 208 | resets the value to 0, 209 | and decrementing below 0 210 | resets it to the maximum. 211 | 212 | * For ''cycle-on'', 213 | incrementing past the maximum 214 | resets the value to 1, 215 | and decrementing it below 1 216 | resets it to the maximum. 217 | 218 | (In other words, 219 | the toggle "stays on" 220 | once it reaches an [=active value=], 221 | rather than cycling back to an [=inactive value=].) 222 | 223 | * For ''sticky'', 224 | incrementing past the maximum value 225 | resets the value to the maximum, 226 | and decrementing it below 0 227 | resets it to 0. 228 |
229 |
230 | 231 | [=Toggles=] are persistent state on an element. 232 | Once created, none of their items are affected by CSS, 233 | and only their [=toggle/value=] can be changed by user interaction. 234 | (Scripting can change the other items, however; 235 | see [[#dom]].) 236 | An element can have any number of [=toggles=]. 237 | 238 |
239 | To match values, 240 | given |toggle| (a [=toggle=]), 241 | a test value |test value| (an integer or <>), 242 | and optionally |states| 243 | (a [=toggle/states=] value): 244 | 245 | 1. If |states| was not passed, 246 | let |states| be |toggle|'s own [=toggle/states=] value. 247 | 248 | 2. Let |toggle value| be |toggle|'s value. 249 | 250 | 3. If |toggle value| and |test value| are both integers, 251 | and the same integer, 252 | return true. 253 | 254 | 4. If |toggle value| and |test value| are both <>s, 255 | and are [=identical to=] each other, 256 | return true. 257 | 258 | 5. If |states| is a list of <>s, 259 | and |toggle value| is a <> in the list, 260 | set |toggle value| to its index in the list. 261 | 262 | Do the same for |test value| if it is a <>. 263 | 264 | If |toggle value| and |test value| are now both the same integer, 265 | return true. 266 | 267 | 6. Otherwise, return false. 268 |
269 | 270 | ---- 271 | 272 | A toggle specifier is a [=struct=] 273 | associated with an element, 274 | with the same structure as a [=toggle=]. 275 | They serve multiple roles: 276 | they specify what [=toggles=] the element is expected to have on it 277 | (creating fresh ones if they don't exist), 278 | provide default values for the newly-created [=toggle's=] items, 279 | and override a [=toggle's=] default behavior when it receives a [=toggle activation=]. 280 | 281 | [=Toggle specifiers=] are defined by the 'toggle-root' property; 282 | they are not persistent state on the element. 283 | An element can have any number of [=toggle specifiers=]. 284 | 285 | ---- 286 | 287 | A toggle group is a [=struct=] associated with an [=element=], 288 | which groups together toggles of the same name 289 | so that only one can be in an [=active value=] at a time. 290 | [=Toggle groups=] have the following [=struct/items=]: 291 | 292 |
293 | : name 294 | :: A <>. 295 | 296 | : scope 297 | :: 298 | An enum indicating what sort of [=toggle/scope=] the [=toggle group=] uses. 299 | It can have two values: 300 | 301 | * "wide", indicating the toggle has [=toggle/wide scope=] 302 | (it's visible to the element, its descendants, 303 | and its following siblings and their descendants). 304 | * "narrow", indicating the toggle has [=toggle/narrow scope=] 305 | (it's visible to the element and its descendants only). 306 |
307 | 308 | [=Toggle groups=] are defined by the 'toggle-group' property; 309 | they are not persistent state on an element. 310 | An element can have any number of [=toggle groups=]. 311 | 312 | A [=toggle=] is in a toggle group 313 | if its [=toggle/group=] boolean is true; 314 | if the element is [=in scope=] for a [=toggle group=] 315 | with the same [=toggle/name=] as the [=toggle=], 316 | it's in that group; 317 | otherwise, it's in a document-wide implicit toggle group 318 | with the same [=toggle/name=]. 319 | 320 | ---- 321 | 322 | [=Toggles=] and [=toggle groups=] have a scope, 323 | defining what additional elements 324 | (beyond the element the [=toggle=]/[=toggle group=] is on) 325 | can see and interact with the [=toggle=]/[=toggle group=]. 326 | 327 | If the [=toggle=] ([=toggle group=]) has wide scope, 328 | it's visible to the element it's defined on, 329 | its descendants 330 | its [=tree/following=] [=tree/siblings=], 331 | and their [=tree/descendants=]. 332 | 333 | If the [=toggle=] ([=toggle group=]) has narrow scope, 334 | it's visible to the element it's defined on 335 | and its descendants. 336 | 337 | [=Toggles=] of the same [=toggle/name=] "shadow" earlier ones; 338 | if multiple toggles of a given [=toggle/name=] would have overlapping scopes, 339 | an element is only in scope 340 | for the [=toggle=] created by the nearest [=preceding=] element in [=tree order=]. 341 | The same applies to [=toggle groups=]. 342 | However, [=toggles=] and [=toggle groups=] do not interfere with each other's scopes; 343 | an element can "see past" a [=toggle=] to find a [=toggle group=] of the same name it's [=in scope=] for, 344 | and vice versa. 345 | 346 | 347 |

348 | Toggles and CSS Properties

349 | 350 | To allow for toggles to be responded to by Selectors 351 | without causing any circularity issues, 352 | [=toggles=] themselves are invisible state on an element, 353 | separate from any CSS properties that might apply. 354 | The CSS properties merely define which elements can activate a toggle, 355 | and which elements can respond to a toggle activation 356 | (and how they do so). 357 | 358 |
359 | For example, while an element needs 'toggle-root' to establish a toggle, 360 | once a toggle is created, 361 | removing the 'toggle-root' property does not affect the toggle. 362 | 363 |
 364 | 		.toggleable {
 365 | 			toggle-root: --foo 1;
 366 | 			toggle-trigger: --foo;
 367 | 		}
 368 | 		.toggleable:toggle(--foo) {
 369 | 			toggle-root: none;
 370 | 			toggle-trigger: none;
 371 | 		}
 372 | 		
373 | 374 | In this example, the toggleable element declares that it can establish a ''foo'' toggle, 375 | and activate it. 376 | During a rendering update, 377 | the ''foo'' toggle is created on the element 378 | (initially with a value of 0, its [=inactive value=]); 379 | when the element is clicked, it's incremented to its [=active value=] (1). 380 | 381 | At this point, the '':toggle(--foo)'' rule begins to match, 382 | and removes the ''toggle-*'' properties. 383 | This does not remove the ''foo'' toggle or affect its value, however; 384 | it still exists and is still set to ''1'', 385 | so the '':toggle()'' pseudo-class will continue matching. 386 | However, further activations of the element 387 | will no longer affect the ''foo'' toggle, 388 | since 'toggle-trigger' was changed to ''toggle-trigger/none''. 389 | 390 | The ''foo'' toggle is thus "frozen" in the activated state 391 | (unless the author has other elements in the toggle's [=toggle/scope=] that can also affect it, 392 | or tweaks the value manually via JS). 393 |
394 | 395 | 396 | 405 | 406 |

407 | Creating a Toggle: the 'toggle-root' property

408 | 409 |
 410 | 	Name: toggle-root
 411 | 	Value: none | <>#
 412 | 	Initial: none
 413 | 	Applies to: all elements
 414 | 	Inherited: no
 415 | 	Percentages: n/a
 416 | 	Media: interactive
 417 | 	Computed value: as specified
 418 | 	Animatable: no
 419 | 	
420 | 421 |
 422 | 		<> =
 423 | 			<>
 424 | 			[
 425 | 				<> [at <>]? ||
 426 | 				<> ||
 427 | 				group ||
 428 | 				self
 429 | 			]?
 430 | 		<> = <> | '[' <>{2,} ']'
 431 | 		<> = <> | <>
 432 | 		<> = cycle | cycle-on | sticky
 433 | 	
434 | 435 | The 'toggle-root' property causes [=toggles=] to be created on an element, 436 | and controls how the [=toggles=] are updated when they are activated. 437 | 438 |
439 |
none 440 |
441 | The element has no [=toggle specifiers=]. 442 | 443 | (This does not remove any [=toggles=] that have already been established 444 | on the element.) 445 | 446 |
<># 447 |
448 | The element has one or more [=toggle specifiers=], 449 | one per <>, 450 | which determine how toggles will be initially created 451 | if they don't already exist on the element, 452 | and how they react to being activated. 453 | 454 | Each <> is composed of several parts, 455 | most of which are optional, 456 | corresponding to the [=struct/items=] of a [=toggle specifier=]. 457 | They specify how the newly-created [=toggle=] 458 | will be set up: 459 | 460 | * The initial <> 461 | specifies the [=toggle specifier/name=]. 462 | 463 | * The <> specifies the [=toggle specifier/states=]. 464 | If specified as an <>, 465 | it sets [=toggle specifier/states=] to the given number; 466 | if specified as a bracketed list of <>s, 467 | it sets [=toggle specifier/states=] 468 | to a list containing those identifiers. 469 | If omitted, defaults to ''1''. 470 | 471 | If <> is a bracketed list, 472 | and there are any repeated <>s among its items, 473 | the property is invalid. 474 | 475 | * The <>, if specified, 476 | specifies the initial [=toggle specifier/value=]. 477 | If omitted, it's set to 0. 478 | 479 | * The <> keyword, if specified, 480 | specifies the [=toggle specifier/overflow=] enum. 481 | If omitted, it's set to "cycle". 482 | 483 | * The group keyword, if specified, 484 | sets the [=toggle specifier/group=] boolean to true. 485 | If omitted, it's set to false. 486 | 487 | * The self keyword, if specified, 488 | sets the [=toggle specifier/scope=] enum to "narrow". 489 | If omitted, it's set to "wide". 490 | 491 | In addition to specifying how to create new [=toggles=], 492 | a [=toggle specifier=] overrides the existing [=toggle's=] 493 | [=toggle/states=], 494 | [=toggle/overflow=], 495 | and [=toggle/group=], 496 | if they differ, 497 | allowing an existing [=toggle=] to have its behavior changed 498 | if necessary. 499 |
500 | 501 |
502 | Revisiting the example in the Introduction, 503 | the same ingredient list can be specified in simple HTML and CSS: 504 | 505 | 506 | <ul class='ingredients'> 507 | <li>1 banana 508 | <li>1 cup blueberries 509 | ... 510 | </ul> 511 | <style> 512 | li { 513 | toggle: --check self; 514 | } 515 | li:toggle(--check) { 516 | color: silver; 517 | text-decoration: line-through; 518 | } 519 | </style> 520 | 521 | 522 | The effect is identical to what was specified in the Introduction example, 523 | except the markup is much simpler and more semantic. 524 |
525 | 526 |

527 | Toggle Creation Details

528 | 529 | Each [=element=] has a list of established toggles, 530 | representing [=toggles=] on the element. 531 | These are created automatically by the 'toggle-root' property, 532 | and/or manually by interacting with the {{Element/toggles|Element.toggles}} map. 533 | 534 | Issue: Define the precise point in [=update the rendering=] 535 | when toggles are created 536 | if 'toggle-root' names a toggle that doesn't exist on the element yet. 537 | 538 | 539 | 548 | 549 |

550 | Linking Toggle Values: the 'toggle-group' property

551 | 552 |
 553 | 	Name: toggle-group
 554 | 	Value: none | [ <> self? ]#
 555 | 	Initial: none
 556 | 	Applies to: all elements
 557 | 	Inherited: no
 558 | 	Percentages: n/a
 559 | 	Media: interactive
 560 | 	Computed value: as specified
 561 | 	Animatable: no
 562 | 	
563 | 564 | By default, each [=toggle's=] [=toggle/value=] is independent; 565 | incrementing one has no effect an any other. 566 | The 'toggle-group' property allows elements to link their [=toggles=] together: 567 | all [=toggles=] with the same [=toggle/name=] as the [=toggle group=] 568 | that are on elements [=toggle/in scope=] for the [=toggle group=] 569 | are linked, 570 | such that only one can be in an [=active value=] at a time, 571 | similar to HTML's <input type=radio> element. 572 | 573 |
574 |
none 575 |
576 | The element does not define a [=toggle group=]. 577 | 578 |
[<> self?]# 579 |
580 | The element defines one or more [=toggle groups=], 581 | one per comma-separated item: 582 | 583 | * The <> 584 | specifies the [=toggle group/name=], 585 | as the item's value. 586 | 587 | * The ''toggle-group/self'' keyword, if specified, 588 | sets the [=toggle group/scope=] enum to "narrow". 589 | If omitted, it's set to "wide". 590 | 591 | Only one [=toggle=] [=in a toggle group=] can be in an [=active value=] at a time; 592 | see 'toggle-trigger' for details. 593 |
594 | 595 |
596 | For example, 'toggle-group' can be used to control a tabbed display, 597 | so that only one panel is displayed at a time: 598 | 599 | 600 | <panel-set> 601 | <panel-tab>first tab</panel-tab> 602 | <panel-card>first panel</panel-card> 603 | <panel-tab>second tab</panel-tab> 604 | <panel-card>second card</panel-card> 605 | ... 606 | </panel-set> 607 | <style> 608 | panel-set { 609 | /* The common ancestor sets up a group */ 610 | toggle-group: --tab; 611 | } 612 | panel-tab { 613 | /* Each tab creates a cycle-on toggle 614 | (so once it's open, clicking again won't close it), 615 | opts into the group, 616 | and declares itself a toggle activator */ 617 | toggle: --tab 1 group cycle-on; 618 | } 619 | panel-tab:first-of-type { 620 | /* The first tab also sets its initial value 621 | to be active */ 622 | toggle: --tab 1 at 1 group cycle-on; 623 | } 624 | panel-tab:toggle(--tab) { 625 | /* styling for the active tab */ 626 | } 627 | panel-card { 628 | /* cards are hidden by default */ 629 | display: none; 630 | } 631 | panel-card:toggle(--tab) { 632 | display: block; 633 | } 634 | </style> 635 | 636 | 637 | Clicking on any tab will increment its corresponding [=toggle's=] [=toggle/value=] from 0 to 1 638 | (and the ''cycle-on'' keyword will keep it at 1 if activated multiple times), 639 | while resetting the rest of the tabs' [=toggle/values=] to 0. 640 | Each panel is [=in scope=] for the [=toggle=] defined by its preceding tab, 641 | so it can respond to the [=toggle/value=] as well. 642 | 643 | Issue: Using 'toggle-visibility' rather than 'display' 644 | is a much better practice; 645 | I should probably change this to that. 646 |
647 | 648 |
649 | Radio buttons have one particular tabbing/switching/activation behavior 650 | (they occupy a single tabindex spot; 651 | once reached you can move between them with arrow keys; 652 | moving to one auto-activates it), 653 | but not all groups will want that behavior. 654 | Accordions, in particular, probably don't, 655 | and instead just want to effectively be independent checkboxes 656 | that happen to only have one active at a time. 657 | 658 | We probably want to add a bool to toggle groups dictating this; 659 | are there more than these two behaviors to deal with? 660 |
661 | 662 | 663 | 672 | 673 |

674 | Activating a Toggle: the 'toggle-trigger' property

675 | 676 |
 677 | 	Name: toggle-trigger
 678 | 	Value: none | <>#
 679 | 	Initial: none
 680 | 	Applies to: elements without existing activation behavior (see prose)
 681 | 	Inherited: no
 682 | 	Percentages: n/a
 683 | 	Media: interactive
 684 | 	Computed value: the keyword ''toggle-trigger/none'', or a list of <> values
 685 | 	Animatable: no
 686 | 	
687 | 688 |
 689 | 		<> = <> <>?
 690 | 		<> =
 691 | 			[prev | next] <>? |
 692 | 			set <>
 693 | 	
694 | 695 | The 'toggle-trigger' property specifies that an element can be activated 696 | to change the value of one or more [=toggles=]. 697 | It has the following values: 698 | 699 | ISSUE: Consider adding support for an at-rule that defines machine states, 700 | the available events to trigger from each state, 701 | and the resulting state of each event. 702 | In that case <> would need to also accept custom events, 703 | possibly marked by a new keyword or function. 704 | 705 |
706 | : none 707 | :: 708 | The element does not manipulate any [=toggles=]. 709 | 710 | : <> 711 | :: 712 | If the <> is omitted, 713 | it defaults to ''next 1''. 714 | If the <> specifies ''prev'' or ''next'', 715 | but omits the following <>, 716 | it defaults to ''1''. 717 | 718 | If the element already has existing activation behavior from the host language, 719 | this value does nothing. 720 | 721 | Otherwise, the element becomes activatable, 722 | and when activated, 723 | for each comma-separated entry in the list, 724 | [=fires a toggle activation=] 725 | with the given <> as a [=toggle activation/name=], 726 | and the <> [=toggle activation/action=]. 727 |
728 | 729 | A toggle activation is a struct with the following items: 730 | 731 |
732 | : name 733 | :: The [=toggle/name=] of the [=toggle=] 734 | this is intended to activate. 735 | 736 | : action 737 | :: A <> value. 738 |
739 | 740 |
741 | To fire a toggle activation 742 | on an element |initial element| 743 | with a [=toggle activation=] |activation|: 744 | 745 | 1. Let |el| initially be |initial element|. 746 | 747 | 2. If |el| has a [=toggle=] 748 | with the same [=toggle/name=] as |activation|, 749 | and |initial element| is [=in scope=] for the [=toggle=], 750 | proceed to the next step. 751 | Otherwise, continue searching for a [=toggle=]: 752 | 753 | * If |el| has a [=previous sibling=], 754 | set |el| to that element 755 | and return to step 2. 756 | * Otherwise, if |el| has a [=parent=] element, 757 | set |el| to that element 758 | and return to step 2. 759 | * Otherwise, return. (No toggle was found, so nothing happens.) 760 | 761 | 3. Let |t| be the [=toggle=] on |el| 762 | with the same [=toggle/name=] as |activation|. 763 | 764 | Let |old value| be |t|'s [=toggle/value=]. 765 | 766 | Let |tSpec| be the [=toggle specifier=] on |el| 767 | with the same [=toggle specifier/name=] as |activation|, 768 | if one exists. 769 | 770 | [=Change a toggle=] |t|, 771 | passing |activation|'s [=toggle activation/action=], 772 | and an override spec of |tSpec| 773 | if it exists. 774 | 775 | Let |new value| be |t|'s [=toggle/value=]. 776 | 777 | 4. If |old value| and |new value| are different, 778 | [=fire a toggle change event=] at |el| for the toggle |t|. 779 |
780 | 781 |
782 | To change a toggle |t|, 783 | given an [=toggle activation/action=] |action|, 784 | and optionally a [=toggle specifier=] |override spec|: 785 | 786 | 1. If |override spec| was passed, 787 | let |states|, |group|, and |overflow| 788 | be the correspondingly-named items from |override spec|. 789 | 790 | Otherwise, let |states|, |group|, and |overflow| 791 | be the correspondingly-named items from |t|. 792 | 793 | 2. If |action| starts with the keyword ''set'', 794 | then change |t|'s value 795 | to the value specified by |action|. 796 | 797 | If |t| does not [=match values|match=] 0, 798 | given |states|, 799 | and |group| is true, 800 | then set the [=toggle/value=] of all other [=toggles=] 801 | [=in a toggle group|in the same toggle group=] as |t| 802 | to 0. 803 | 804 | Return. 805 | 806 | 3. If |t|'s [=toggle/value=] is an integer, 807 | let |index| be that integer. 808 | Otherwise, if |states| is a list of idents 809 | and |t|'s [=toggle/value=] is in the list, 810 | let |index| be the index of the first occurence of the value. 811 | Otherwise, let |index| be infinity. 812 | 813 | 4. If |states| is an integer, 814 | let |max index| be that integer. 815 | Otherwise, let |max index| 816 | be one less than the length of |states|. 817 | 818 | 5. If |action| starts with the keyword ''next'', 819 | then increment |index| by |action|'s value. 820 | Then, based on the value of |overflow|: 821 | 822 |
823 | : ''cycle'' 824 | :: If |index| is greater than |maximum index|, 825 | set |index| to 0. 826 | 827 | : ''cycle-on'' 828 | :: If |index| is greater than |maximum index|, 829 | set |index| to 1. 830 | 831 | : ''sticky'' 832 | :: If |index| is greater than |maximum index|, 833 | set |index| to |maximum index|. 834 |
835 | 836 | Otherwise, if |action| starts with the keyword ''prev'', 837 | then decrement |index| by |action|'s value. 838 | Then, based on the value of |overflow|: 839 | 840 |
841 | : ''cycle'' 842 | :: If |index| is less than 0 843 | or greater than |maximum index|, 844 | set |index| to |maximum index|. 845 | 846 | : ''cycle-on'' 847 | :: If |index| is less than 1 848 | or greater than |maximum index|, 849 | set |index| to |maximum index|. 850 | 851 | : ''sticky'' 852 | :: If |index| is less than 0, 853 | set |index| to 0. 854 | 855 | If |index| is greater than |maximum index|, 856 | set |index| to |maximum index|. 857 |
858 | 859 | 6. If |states| is a list of idents, 860 | and |index| is the index of one of the entries in that list, 861 | set |t|'s [=toggle/value=] to that entry. 862 | 863 | Otherwise, set [=toggle/value=] to |index|. 864 | 865 | 7. If |t| does not [=match values|match=] 0, 866 | given |states|, 867 | and |group| is true, 868 | then set the [=toggle/value=] of all other [=toggles=] 869 | [=in a toggle group|in the same toggle group=] as |t| 870 | to 0. 871 |
872 | 873 | Issue: Define in much greater precision what it means to "become activatable". 874 | The element must become focusable 875 | (with a default spot in the focus order) 876 | and become capable of being activated by mouse/keyboard/etc. 877 | Similarly define the "already activatable" prose in more detail; 878 | we want to exclude things like text inputs, 879 | which would confuse a11y tooling, 880 | but include buttons that aren't, like, submit buttons. 881 | 882 | 883 | 892 | 893 |

894 | Creating and Activating Toggles Simultaneously: the 'toggle' shorthand

895 | 896 |
 897 | 	Name: toggle
 898 | 	Value: <<'toggle-root'>>
 899 | 	
900 | 901 | While some cases require setting up a [=toggle=] on an ancestor 902 | of the elements that will activate and respond to the toggle, 903 | in many cases the [=toggle/scope=] rules for [=toggles=] 904 | are such that it's fine to create the [=toggle=] 905 | on the element intended to activate the toggle as well. 906 | 907 | The 'toggle' shorthand sets both the 'toggle-root' and 'toggle-trigger' properties on an element together. 908 | The entire value of the property is assigned to 'toggle-root', 909 | while 'toggle-trigger' is assigned to just the <>s specified in the list, 910 | if any. 911 | 912 |
913 | For example, 914 | in the following code for an <{spoiler-text}> element, 915 | the show/hide button precedes the content it will show and hide, 916 | so we can just create the toggle on it as well: 917 | 918 | 919 | <spoiler-text> 920 | <summary>...</summary> 921 | <content>...</content> 922 | </spoiler-text> 923 | <style> 924 | spoiler-text > summary { 925 | toggle: --show; 926 | } 927 | spoiler-text > content { 928 | toggle-visibility: --show; 929 | } 930 | </style> 931 | 932 |
933 | 934 |

935 | Accessibility Implications of Toggles

936 | 937 |
938 | TODO 939 | 940 | * a 'toggle-trigger' element needs to become activatable/focusable/etc, 941 | and communicate in the a11y tree that it's a checkbox/radio/etc 942 | * we can infer what type of control it is 943 | by examining the properties of the toggle: 944 | if it's part of a group, cycle-on, etc. 945 | * if 'toggle-visibility' is in use, 946 | we can also automatically infer all the tab-set ARIA roles 947 |
948 | 949 | 950 | 959 | 960 |

961 | Selecting Elements Based on Toggle Value: the '':toggle()'' pseudo-class

962 | 963 | [[SELECTORS-4]] defines the '':checked'' pseudo-class, 964 | which allows author to match certain elements 965 | (as defined by the host language) 966 | depending on their "checked" state. 967 | 968 | [=Toggles=] provides a very similar functionality, 969 | allowing elements to be selected based on their [=toggle=] [=toggle/value=], 970 | the :toggle() pseudo-class: 971 | 972 |
 973 | 		:toggle( <> <>? )
 974 | 	
975 | 976 | An element matches '':toggle()'' 977 | if the element is [=in scope=] for a [=toggle=] 978 | with the [=toggle/name=] given by <>, 979 | and either the [=toggle=] 980 | [=match values|matches=] the provided <>, 981 | or the <> is omitted 982 | and the [=toggle=] is in any [=active value=]. 983 | 984 |
985 | For example, if a [=toggle=] named "used" 986 | is defined on each element in an recipe's ingredient list, 987 | the ingredients can respond to being clicked on easily: 988 | 989 |
 990 | 			.ingredient {
 991 | 				toggle: --used;
 992 | 			}
 993 | 			.ingredient:toggle(--used) {
 994 | 				color: silver;
 995 | 				text-decoration: line-through;
 996 | 			}
 997 | 		
998 |
999 | 1000 |
1001 | A checkbox that can represent an "indeterminate" value 1002 | might have two active values. 1003 | 1004 |
1005 | 			.tristate-check {
1006 | 				toggle: --check 2 at 0;
1007 | 			}
1008 | 			.tristate-check:toggle(--check 1) {
1009 | 				/* "checked" styles */
1010 | 			}
1011 | 			.tristate-check:toggle(--check 2) {
1012 | 				/* "indeterminate" styles */
1013 | 			}
1014 | 		
1015 |
1016 | 1017 |
1018 | While '':not(:toggle(--foo))'' will correctly match an element 1019 | whose "foo" toggle is in an [=inactive value=], 1020 | it will also match any element 1021 | that doesn't see a "foo" toggle at all. 1022 | 1023 | If this is inconvenient, 1024 | only elements that actually know about a particular toggle 1025 | can be targeted by specifying the [=inactive value=] specifically: 1026 | 1027 |
1028 | 			.card:toggle(--show 0) {
1029 | 				/* Definitely *not* shown */
1030 | 			}
1031 | 		
1032 |
1033 | 1034 | 1035 | 1044 | 1045 |

1046 | Automatically Hiding With A Toggle

1047 | 1048 | The 'content-visibility' property 1049 | allows an element to suppress the layout and rendering of its contents, 1050 | similar to ''display: none''; 1051 | however, its ''content-visibility/auto'' value allows the contents 1052 | to still be visible to various searching and accessibility features, 1053 | like find-in-page, 1054 | hash-navigation, 1055 | or tab order, 1056 | and then to automatically become visible 1057 | when the element becomes [=relevant to the user=]. 1058 | 1059 | A common use-case for [=toggles=] is also to control whether an element is shown or hidden, 1060 | and in many cases it would also be useful to allow the contents of elements "hidden" in this way 1061 | to be accessible in the same ways. 1062 | To allow for this, 1063 | the 'toggle-visibility' property allows an element 1064 | to both respond to and control a toggle 1065 | with its visibility. 1066 | 1067 |
1068 | 	Name: toggle-visibility
1069 | 	Value: normal | <>
1070 | 	Initial: normal
1071 | 	Inherited: no
1072 | 	Applies to: all elements
1073 | 	Computed value: as specified
1074 | 	Animation type: not animatable
1075 | 	
1076 | 1077 | The 'toggle-visibility' property 1078 | allows an element to automatically tie its display to a particular [=toggle=] bi-directionally, 1079 | while still exposing its contents to be focused, found-in-page, etc., 1080 | automatically showing itself when relevant. 1081 | 1082 |
1083 | : normal 1084 | :: 1085 | The property has no effect. 1086 | 1087 | : <> 1088 | :: 1089 | If the element is [=in scope=] 1090 | for a [=toggle=] whose name matches the <>, 1091 | and that [=toggle=] is in the [=inactive value=], 1092 | then the element acts as if ''content-visibility: auto'' is specified, 1093 | except that being on-screen does not make it [=relevant to the user=]. 1094 | 1095 | If the element starts being [=relevant to the user=], 1096 | it [=fires=] a [=toggle activation=], 1097 | with a [=toggle activation/name=] of the given <> 1098 | and a [=toggle activation/action=] of ''set 1''. 1099 | 1100 | Note: If the [=toggle=] is in an [=active value=], 1101 | or the element can't see the specified [=toggle=] at all, 1102 | the element renders normally. 1103 |
1104 | 1105 |
1106 | For example, an "accordion" display, 1107 | such as used for a page of FAQs, 1108 | can use 'toggle-visibility' to hide the answers by default, 1109 | but still make them accessible to find-in-page: 1110 | 1111 | 1112 | <dl class=accordion> 1113 | <dt>Question 1? 1114 | <dd>Long answer...... 1115 | <dt>Question 2? 1116 | <dd>Another long answer..... 1117 | </dl> 1118 | <style> 1119 | .accordion > dt { 1120 | toggle: --show; 1121 | } 1122 | .accordion > dd { 1123 | toggle-visibility: --show; 1124 | } 1125 | </style> 1126 | 1127 | 1128 | Each <{dt}> establishes a separate "show" [=toggle=], 1129 | with all the defaults filling in to produce a standard "checkbox"-like behavior, 1130 | all initially in the [=inactive value=]. 1131 | Each <{dt}> can be activated to show or hide the following answer. 1132 | 1133 | Each <{dd}> can see the [=toggle=] established by its preceding <{dt}>, 1134 | and will start out not rendering. 1135 | If the user searches on the page for a term, 1136 | or visits the page from a link with an #anchor linking into one of the answers, 1137 | the relevant answer will automatically activate the [=toggle=], 1138 | causing the <{dd}> to become visible. 1139 |
1140 | 1141 | Issue: Define ordering of activations, 1142 | so if multiple elements become relevant at the same time 1143 | and they're all part of a [=toggle group=], 1144 | which one "wins" is well-defined. 1145 | 1146 | 1147 | 1148 | 1157 | 1158 |

1159 | Scripting API

1160 | 1161 |

1162 | {{CSSToggleMap}}

1163 | 1164 | 1165 | partial interface Element { 1166 | [SameObject] readonly attribute CSSToggleMap toggles; 1167 | }; 1168 | 1169 | interface CSSToggleMap { 1170 | maplike<DOMString, CSSToggle>; 1171 | CSSToggleMap set(DOMString key, CSSToggle value); 1172 | }; 1173 | 1174 | 1175 | The {{Element/toggles}} attribute on {{Element}}s 1176 | represents the [=established toggles=] on the element: 1177 | each [=toggle=] is represented by an [=map/entry=] in the map, 1178 | with its key equal to its [=toggle/name=] 1179 | and its value a {{CSSToggle}} representing the rest of the [=toggle's=] data. 1180 | 1181 | Entries can be automatically added to {{Element/toggles}} 1182 | by the 'toggle-root' property 1183 | when [=update the rendering=] occurs, 1184 | if 'toggle-root' defines a [=toggle specifier=] 1185 | whose name doesn't exist in {{Element/toggles}} yet; 1186 | see [[#toggle-creation]] for details. 1187 | 1188 |
1189 | The set(|key|, |value|) 1190 | [=method steps=] are: 1191 | 1192 | 1. If |key| does not start with "--" (two U+002D HYPHEN-MINUS characters), 1193 | [=throw=] a {{SyntaxError}}. 1194 | 1195 | 2. If |value|'s {{[[ToggleMap]]}} internal slot is non-{{undefined}}, 1196 | then let |oldMap| be the [=map entries=] of the slot's value, 1197 | and [=map/remove=] the entry from |oldMap| whose value is |value|. 1198 | 1199 | 3. Set |value|'s {{[[ToggleMap]]}} internal slot to [=this=]. 1200 | 1201 | 4. Let |map| be [=this's=] [=map entries=]. Set |map|[|key|] to |value|. 1202 | 1203 | 5. Return [=this=]. 1204 | 1205 | Note: A given {{CSSToggle}} can only live in one {{CSSToggleMap}} at a time. 1206 | This avoids some otherwise confusing or ambiguous situations. 1207 |
1208 | 1209 |

1210 | {{CSSToggle}}

1211 | 1212 | 1213 | interface CSSToggle { 1214 | attribute (unsigned long or DOMString) value; 1215 | attribute unsigned long? valueAsNumber; 1216 | attribute DOMString? valueAsString; 1217 | 1218 | attribute (unsigned long or FrozenArray<DOMString>) states; 1219 | attribute boolean group; 1220 | attribute CSSToggleScope scope; 1221 | attribute CSSToggleCycle cycle; 1222 | 1223 | constructor(optional CSSToggleData options); 1224 | }; 1225 | 1226 | dictionary CSSToggleData { 1227 | (unsigned long or DOMString) value = 0; 1228 | (unsigned long or sequence<DOMString>) states = 1; 1229 | boolean group = false; 1230 | CSSToggleScope scope = "wide"; 1231 | CSSToggleCycle cycle = "cycle"; 1232 | }; 1233 | 1234 | enum CSSToggleScope { 1235 | "narrow", 1236 | "wide", 1237 | }; 1238 | 1239 | enum CSSToggleCycle { 1240 | "cycle", 1241 | "cycle-on", 1242 | "sticky", 1243 | }; 1244 | 1245 | 1246 | A {{CSSToggle}} represents a [=toggle=]; 1247 | changing any attribute on the {{CSSToggle}} 1248 | will change the corresponding items of the [=toggle=] it represents, 1249 | and vice versa. 1250 | 1251 | Note: Only the [=toggle/value=] will change directly on a [=toggle=] 1252 | and get reflected back to the {{CSSToggle}}; 1253 | the rest of its items are fixed on creation 1254 | unless manually changed on its associated {{CSSToggle}}. 1255 | 1256 | A {{CSSToggle}} will usually be an [=established toggle=] on an element, 1257 | present in the element's {{Element/toggles}} attribute, 1258 | but can also be used independently. 1259 | This is tracked by a \[[ToggleMap]] internal slot, 1260 | containing either {{undefined}} (the initial value) 1261 | or a weak reference to the {{CSSToggleMap}} the {{CSSToggle}} is in. 1262 | 1263 |
1264 | The new CSSToggle(|options|) [=constructor steps=] are: 1265 | 1266 | 1. [=map/For each=] |name|→|value| in |options|: 1267 | 1268 | 1. If |name| is "states" 1269 | and |value| is a [=/list=]: 1270 | 1271 | * If any of the [=list/items=] of |value| 1272 | are [=string/identical to=] each other, 1273 | [=throw=] a {{SyntaxError}}. 1274 | * If |value|'s [=list/size=] is less than 2, 1275 | [=throw=] a {{SyntaxError}}. 1276 | 1277 | 3. Set the internal slot named |name| of [=this=] 1278 | to |value|. 1279 | 1280 | 2. Return [=this=]. 1281 |
1282 | 1283 |
1284 | The valueAsNumber [=getter steps=] are: 1285 | 1286 | 1. If [=this's=] {{CSSToggle/value}} slot contains an integer, 1287 | return that. 1288 | 1289 | 2. If [=this's=] {{CSSToggle/value}} slot contains a string, 1290 | [=this's=] {{CSSToggle/states}} internal slot is a list, 1291 | and the string is present in that list, 1292 | return the index of the first instance of that string in the list. 1293 | 1294 | 3. Otherwise, return null. 1295 | 1296 | The {{valueAsNumber}} [=setter steps=] are: 1297 | 1298 | 1. If [=the given value=] is an integer, 1299 | [=update the value slot=] of [=this=] to [=the given value=] 1300 | and return. 1301 | 1302 | 2. Otherwise, [=throw=] a {{TypeError}} exception. 1303 | 1304 | The {{valueAsNumber}} attribute does not have a corresponding internal slot. 1305 |
1306 | 1307 |
1308 | The valueAsString [=getter steps=] 1309 | are: 1310 | 1311 | 1. If [=this's=] {{CSSToggle/value}} internal slot contains an string, 1312 | return that. 1313 | 1314 | 2. If [=this's=] {{CSSToggle/value}} internal slot contains an index, 1315 | and [=this's=] {{CSSToggle/states}} internal slot is a list 1316 | and has an entry corresponding to that index, 1317 | return that entry. 1318 | 1319 | 3. Otherwise, return null. 1320 | 1321 | The {{valueAsString}} [=setter steps=] are: 1322 | 1323 | 1. If [=the given value=] is an string, 1324 | [=update the value slot=] of [=this=] to [=the given value=] 1325 | and return. 1326 | 1327 | 2. Otherwise, [=throw=] a {{TypeError}} exception. 1328 | 1329 | The {{valueAsString}} attribute does not have a corresponding internal slot. 1330 |
1331 | 1332 |
1333 | The value [=setter steps=] 1334 | are to [=update the value slot=] of [=this=] to [=the given value=]. 1335 |
1336 | 1337 |
1338 | To update the value slot 1339 | of a {{CSSToggle}} [=this=] 1340 | to a new value |val|: 1341 | 1342 | 1. If [=this=] is an [=established toggle=], 1343 | then [=change a toggle=] [=this=], 1344 | with an [=toggle activation/action=] 1345 | of ''set'' followed by |val|. 1346 | 1347 | Note: Due to the reflection, 1348 | this will automatically update 1349 | the {{CSSToggle/value}} internal slot of [=this=] as well. 1350 | 1351 | 2. Otherwise, 1352 | set the {{CSSToggle/value}} internal slot of [=this=] 1353 | to |val|. 1354 |
1355 | 1356 |
1357 | The states [=setter steps=] are: 1358 | 1359 | 1. If [=the given value=] is a sequence of {{DOMString}}s: 1360 | 1361 | * If any of the [=list/items=] of [=the given value=] 1362 | are [=string/identical to=] each other, 1363 | [=throw=] a {{SyntaxError}}. 1364 | * If [=the given value's=] [=list/size=] is less than 2, 1365 | [=throw=] a {{SyntaxError}}. 1366 | 1367 | 2. Set [=this's=] {{CSSToggle/states}} internal slot to [=the given value=]. 1368 |
1369 | 1370 |

1371 | {{CSSToggleEvent}}

1372 | 1373 | 1374 | interface CSSToggleEvent : Event { 1375 | constructor(DOMString type, optional CSSToggleEventInit eventInitDict = {}); 1376 | readonly attribute DOMString toggleName; 1377 | readonly attribute CSSToggle? toggle; 1378 | }; 1379 | 1380 | dictionary CSSToggleEventInit : EventInit { 1381 | DOMString toggleName = ""; 1382 | CSSToggle? toggle = null; 1383 | }; 1384 | 1385 | 1386 | Issue: whatwg/dom#600 1387 | means apparently events don't yet work 1388 | if their init dictionaries have required members. 1389 | Neither of these have reasonable defaults, 1390 | especially the toggle part, 1391 | but oh well I guess. 1392 | 1393 |
1394 | To fire a toggle change event 1395 | at an {{Element}} |el| 1396 | for a [=toggle=] |toggle| 1397 | means to 1398 | [=fire an event=] named "togglechange" 1399 | using {{CSSToggleEvent}}, 1400 | setting {{CSSToggleEvent/toggleName}} to |toggle|'s [=toggle/name=] 1401 | and {{CSSToggleEvent/toggle}} to the entry of |el|'s {{Element/toggles}} map 1402 | with |toggle|'s [=toggle/name=] as the key. 1403 |
--------------------------------------------------------------------------------