<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Steeve</title>
    <description>The latest articles on Forem by Steeve (@steeve).</description>
    <link>https://forem.com/steeve</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F139795%2Fbe23062f-bf44-44c9-bfcc-1eec6b9ea66a.jpg</url>
      <title>Forem: Steeve</title>
      <link>https://forem.com/steeve</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/steeve"/>
    <language>en</language>
    <item>
      <title>Cheat Sheet for Carbone</title>
      <dc:creator>Steeve</dc:creator>
      <pubDate>Thu, 20 Nov 2025 09:00:00 +0000</pubDate>
      <link>https://forem.com/carbone/cheat-sheet-for-carbone-2ikd</link>
      <guid>https://forem.com/carbone/cheat-sheet-for-carbone-2ikd</guid>
      <description>&lt;p&gt;Carbone is a templating engine designed to generate dynamic documents (PDFs, DOCX, XLSX, PPTX, etc.) by merging templates with JSON data:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The JSON Data-set&lt;/strong&gt; coming from your application, database, or API.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The template&lt;/strong&gt; must be designed using a Text Editor like Word, LibreOffice or Google Docs. To inject the content dynamically you must write &lt;strong&gt;Tags&lt;/strong&gt; (a.k.a. placeholder), it will be replaced with the corresponding values from the JSON data. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Carbone’s tag syntax offers a lot of possibilities! This article focuses on the essentials, but if you want to dive deeper or see more examples, check out the &lt;a href="https://carbone.io/documentation/design/substitutions/the-basics.html" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm07qj238f4bggmcrecve.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm07qj238f4bggmcrecve.png" alt="Carbone Templating Syntax Cheat Cheet" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://carbone.io/blog/carbone-templating-cheat-sheet/" rel="noopener noreferrer"&gt;Click to download the Cheat Sheet without image compression&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Essential Carbone Templating Syntax
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Basic Placeholder
&lt;/h3&gt;

&lt;p&gt;The placeholder tag injects the value of a property from the root of the JSON data object (d). It is the simplest way to insert dynamic data into your template. For instance, if the JSON dataset is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; 
  &lt;/span&gt;&lt;span class="nl"&gt;"firstname"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"John"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Insert the following tag in the template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{d.firstname}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and it will be replaced with "John" in the generated document.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Nested Placeholder
&lt;/h3&gt;

&lt;p&gt;This tag accesses nested properties in the JSON data. It allows you to traverse deeper into the JSON structure to retrieve specific values. There is no limit to access in depth of nested properties. For instance, If your JSON is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"user"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Alice"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tag in the template file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{d.user.name}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;will be replaced with "Alice".&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Access Parent Property
&lt;/h3&gt;

&lt;p&gt;The double dot &lt;strong&gt;(..)&lt;/strong&gt; notation lets you access a property of the parent object from a nested context. To access the grandparent object’s property, use three dots &lt;strong&gt;(...)&lt;/strong&gt;. You can chain as many dots as needed to navigate up the object hierarchy. If your JSON is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "country": "France",
  "movie": {
    "name": "Inception", 
    "sub": {
      "a" : "test"
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tag in the template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{d.movie.sub..name}
{d.movie.sub...country} 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first tag will be replaced with "Inception".&lt;br&gt;
The second tag will be replaced with "France"&lt;/p&gt;
&lt;h3&gt;
  
  
  4. Array Access with Static Index
&lt;/h3&gt;

&lt;p&gt;This tag accesses a specific element in an array by its index using the square bracket notation &lt;strong&gt;[index]&lt;/strong&gt;. It is useful for retrieving a particular item from an array without looping. If your JSON is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "movies": [
    { "name": "Inception" },
    { "name": "Matrix" }
  ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tag in the template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{d.movies[0].name}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;will be replaced with "Inception".&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Conditional Logic
&lt;/h3&gt;

&lt;p&gt;This tag uses the &lt;strong&gt;:ifEQ&lt;/strong&gt; formatter to check if a value meets a specific condition. If the condition is met, it prints the specified text. It exists many conditional formatters (e.g. &lt;strong&gt;:ifIN&lt;/strong&gt;, &lt;strong&gt;:ifGT&lt;/strong&gt;,  etc...), and it can be chained (using &lt;strong&gt;:and&lt;/strong&gt;, &lt;strong&gt;:or&lt;/strong&gt;) for complex logic and used in inline conditions, or conditional sections. If your JSON is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"isActive"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Your subscription is disabled."&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tag in the template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{d.isActive:ifEQ(true):show('Yes'):elseShow(.message)}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;will be replaced with the static text "Yes" if the value is true, otherwise the value of the "message" field is printed.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Default Value
&lt;/h3&gt;

&lt;p&gt;Still using conditional formatters, the &lt;strong&gt;:ifEM&lt;/strong&gt; formatter checks if a value is empty (null, undefined, empty string, empty array, or empty object). If it is, it prints the specified default value. If your JSON is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"user"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tag in the template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{d.user.name:ifEM:show('Unknown')}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;will be replaced with the static text "Unknown".&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Loop (Array Iteration)
&lt;/h3&gt;

&lt;p&gt;Use the square bracket notation &lt;strong&gt;[i]&lt;/strong&gt; to iterate over arrays, The character &lt;strong&gt;i&lt;/strong&gt; is the loop iterator (automatically managed by Carbone). Then insert the &lt;strong&gt;[i+1]&lt;/strong&gt; tag, which signals the end of the pattern and is automatically removed during rendering. &lt;/p&gt;

&lt;p&gt;This allows you to repeat content for each item in an array. If your JSON is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"users"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Alice"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"role"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Admin"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Bob"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"role"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Editor"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Charlie"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"role"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Viewer"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tag in the template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{d.users[i].id} - {d.users[i].name}
&amp;lt;!-- End of loop pattern --&amp;gt;
{d.users[i+1]}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;will print each user's id and name in a new line.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: You do not need to repeat each &lt;strong&gt;[i]&lt;/strong&gt; tag with &lt;strong&gt;[i+1]&lt;/strong&gt;, just the one &lt;strong&gt;[i+1]&lt;/strong&gt; is enough for Carbone to recognize the loop pattern.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  8. Loop of Nested Arrays
&lt;/h3&gt;

&lt;p&gt;Use the square bracket notation &lt;strong&gt;[i]&lt;/strong&gt; and &lt;strong&gt;[i+1]&lt;/strong&gt; (explained the previous point) to iterate over arrays, including nested ones. You can nest loops as deeply as needed. Finally, always use &lt;strong&gt;i&lt;/strong&gt; as the loop iterator, even for nested arrays: Do not ever use "j" or other characters. If your JSON is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"brand"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Toyota"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"models"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"size"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Prius 4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"power"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;125&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"size"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Prius 5"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"power"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;139&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"brand"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Kia"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"models"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"size"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EV4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"power"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;450&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"size"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EV6"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"power"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tags loops in the template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{d[i].brand}
Models
{d[i].models[i].size} - {d[i].models[i].power}
{d[i].models[i+1]}
{d[i+1]}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Will generate the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Toyota
Models
Prius 4 - 125
Prius 5 - 139
Kia
Models
EV4 - 450
EV6 - 500
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  9. Filter a Loop
&lt;/h3&gt;

&lt;p&gt;In a loop, it is possible to filters Arrays to only include items that meet a specific condition. Only matching items are printed in the loop. You can add as many conditions as you want, based on the attributes in your list. To filter an array, use the following syntax in your loop tag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{d.array[i, condition1, condition2, ...]}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you have the following JSON:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"items"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Strawberries"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;268&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"category"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"fruit"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Apple"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"category"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"fruit"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Banana"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"category"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"fruit"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Carrot"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"category"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"vegetable"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tag in the template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;{d.items[i, price &amp;gt; 100, category="fruit"].name}
{d.items[i+1, price &amp;gt; 100, category="fruit"]}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;will only print "Strawberries" and "Banana". The loop prints items where the price is greater than 100 and the category is "fruit".&lt;/p&gt;

&lt;h3&gt;
  
  
  10. Sort a Loop
&lt;/h3&gt;

&lt;p&gt;In a loop, it is possible to sorts Array by a one or multiple attributes before iterating over it. The array will be sorted in ascending order based on the first attribute, then by the second attribute if values are equal, and so on. The syntax is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{d.array[attribute1, attribute2, ..., i]}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your JSON is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "items": [
    {"name": "Apple", "power": 2},
    {"name": "Banana", "power": 1}
  ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tag in the template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{d.items[power, i].name}
{d.items[power+1, i+1].name}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;will print "Banana" followed by "Apple". You can specify as many attributes as you want (e.g., &lt;code&gt;power&lt;/code&gt;, &lt;code&gt;name&lt;/code&gt;, etc.). &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Important note: while sorting, the &lt;strong&gt;i&lt;/strong&gt; iterator must always be the last element in the squared brackets.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  11. Formatters
&lt;/h3&gt;

&lt;p&gt;Formatters are functions appended to tags with a colon (:) that modify data before display. They can accept static or dynamic parameters.&lt;/p&gt;

&lt;h4&gt;
  
  
  11.1 Text Formatters
&lt;/h4&gt;

&lt;p&gt;These formatters transform text in various ways, such as changing case, extracting substrings, replacing text, and more.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Formatter&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;:lowerCase()&lt;/td&gt;
&lt;td&gt;Converts text to lowercase&lt;/td&gt;
&lt;td&gt;{d.name:lowerCase()}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:upperCase()&lt;/td&gt;
&lt;td&gt;Converts text to uppercase&lt;/td&gt;
&lt;td&gt;{d.name:upperCase()}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:substr(start, length)&lt;/td&gt;
&lt;td&gt;Extracts a substring&lt;/td&gt;
&lt;td&gt;{d.text:substr(0, 5)}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:replace(search, replace)&lt;/td&gt;
&lt;td&gt;Replaces text&lt;/td&gt;
&lt;td&gt;{d.text:replace('old', 'new')}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:len()&lt;/td&gt;
&lt;td&gt;Returns the length of a string or array&lt;/td&gt;
&lt;td&gt;{d.text:len()}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:convCRLF()&lt;/td&gt;
&lt;td&gt;Converts line breaks to &lt;code&gt;&amp;lt;br&amp;gt;&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;{d.text:convCRLF()}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:preserveCharRef()&lt;/td&gt;
&lt;td&gt;Preserves character references&lt;/td&gt;
&lt;td&gt;{d.text:preserveCharRef()}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:t&lt;/td&gt;
&lt;td&gt;Translates text (Learn more on the dedicated section below)&lt;/td&gt;
&lt;td&gt;{d.greeting:t}&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h4&gt;
  
  
  11.2 Number Formatters
&lt;/h4&gt;

&lt;p&gt;These formatters format numbers, including setting precision, rounding, and performing arithmetic operations.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Formatter&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;:formatN(decimals)&lt;/td&gt;
&lt;td&gt;Formats  with the specified number of decimal places.&lt;/td&gt;
&lt;td&gt;{d.price:formatN(2)}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:round(decimals)&lt;/td&gt;
&lt;td&gt;Rounds with the specified number of decimal places.&lt;/td&gt;
&lt;td&gt;{d.value:round(2)}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:floor()&lt;/td&gt;
&lt;td&gt;Rounds down to the nearest integer.&lt;/td&gt;
&lt;td&gt;{d.value:floor()}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:ceil()&lt;/td&gt;
&lt;td&gt;Rounds up to the nearest integer.&lt;/td&gt;
&lt;td&gt;{d.value:ceil()}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:add(value)&lt;/td&gt;
&lt;td&gt;Adds a value&lt;/td&gt;
&lt;td&gt;{d.value:add(10)}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:sub(value)&lt;/td&gt;
&lt;td&gt;Subtracts a value&lt;/td&gt;
&lt;td&gt;{d.value:sub(10)}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:mul(value)&lt;/td&gt;
&lt;td&gt;Multiplies by a value&lt;/td&gt;
&lt;td&gt;{d.value:mul(2)}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:div(value)&lt;/td&gt;
&lt;td&gt;Divides by a value&lt;/td&gt;
&lt;td&gt;{d.value:div(2)}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:mod(value)&lt;/td&gt;
&lt;td&gt;Modulo operation&lt;/td&gt;
&lt;td&gt;{d.value:mod(2)}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:abs()&lt;/td&gt;
&lt;td&gt;Absolute value&lt;/td&gt;
&lt;td&gt;{d.value:abs()}&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h4&gt;
  
  
  11.3 Currency Formatters
&lt;/h4&gt;

&lt;p&gt;These formatters format numbers as currency, including setting precision and converting between currencies.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Formatter&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;:formatC(precision, currency)&lt;/td&gt;
&lt;td&gt;Formats a number as currency&lt;/td&gt;
&lt;td&gt;{d.price:formatC(2, 'USD')}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:convCurr(source, target)&lt;/td&gt;
&lt;td&gt;Converts currency&lt;/td&gt;
&lt;td&gt;{d.price:convCurr('EUR', 'USD')}&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h4&gt;
  
  
  11.4 Date Formatters
&lt;/h4&gt;

&lt;p&gt;These formatters format dates according to specified patterns.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Formatter&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;:formatD(pattern)&lt;/td&gt;
&lt;td&gt;Formats a date&lt;/td&gt;
&lt;td&gt;{d.date:formatD('YYYY-MM-DD')}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:formatI(pattern)&lt;/td&gt;
&lt;td&gt;Formats an interval&lt;/td&gt;
&lt;td&gt;{d.interval:formatI('HH:mm')}&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h4&gt;
  
  
  11.5 Array Formatters
&lt;/h4&gt;

&lt;p&gt;These formatters manipulate arrays, such as joining elements, and mapping values, and performing aggregations (Process a set of values and returns a single aggregated result).&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Formatter&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;:arrayJoin(separator)&lt;/td&gt;
&lt;td&gt;Joins array elements&lt;/td&gt;
&lt;td&gt;{d.array:arrayJoin(', ')}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:arrayMap(separator, keySeparator, key)&lt;/td&gt;
&lt;td&gt;Maps array elements&lt;/td&gt;
&lt;td&gt;{d.array:arrayMap(', ', ':', 'id')}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:aggStr(separator)&lt;/td&gt;
&lt;td&gt;Aggregator to concatenate array elements&lt;/td&gt;
&lt;td&gt;{d.array[].value:aggStr(', ')}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:aggSum()&lt;/td&gt;
&lt;td&gt;Aggregator to sums array elements&lt;/td&gt;
&lt;td&gt;{d.array[].value:aggSum()}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:aggAvg()&lt;/td&gt;
&lt;td&gt;Aggregator to get the average&lt;/td&gt;
&lt;td&gt;{d.array[].value:aggAvg()}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:aggMin()&lt;/td&gt;
&lt;td&gt;Aggregator to get the minimum value&lt;/td&gt;
&lt;td&gt;{d.array[].value:aggMin()}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:aggMax()&lt;/td&gt;
&lt;td&gt;Aggregator to get the maximum value&lt;/td&gt;
&lt;td&gt;{d.array[].value:aggMax()}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:aggCount()&lt;/td&gt;
&lt;td&gt;Aggregator that return the total number of elements&lt;/td&gt;
&lt;td&gt;{d.cars[sort&amp;gt;20].qty:aggCount}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:cumSum()&lt;/td&gt;
&lt;td&gt;Aggregator for running totals: Calculates and prints the cumulative sum of data&lt;/td&gt;
&lt;td&gt;{d[i].qty:cumSum} {d[i+1]}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:cumCount()&lt;/td&gt;
&lt;td&gt;Aggregator that print a sequential integer to each row in a list.&lt;/td&gt;
&lt;td&gt;{d[i].qty:cumCount} {d[i+1]}&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  12. Colors
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;:color&lt;/strong&gt; formatter lets you dynamically apply colors to text, paragraphs, cells, rows, or shapes in your templates. You specify the target element and the color value from your JSON data. The syntax is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{d.colorValue:color(scope, types)}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your JSON is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "warningHexa": "#FF0000",
  "highlightHexa": "#FFFF00"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tag in the template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!-- For Text --&amp;gt; 
{d.warningHexa:color(p)}This text will be red.
&amp;lt;!-- For Tables --&amp;gt;
{d.highlightHexa:color(cell, background)}This cell will have a yellow background.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;will color the text "This text will be red." in red and the cell background of "This cell will have a yellow background." in Yellow.&lt;/p&gt;

&lt;h3&gt;
  
  
  13. Inject HTML from WYSIWYG or Code Editors
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;:html&lt;/strong&gt; formatter allows you to inject raw HTML strings from your JSON data directly into your template (supported formats: DOCX, ODT and PDF). Without this formatter, "&amp;lt;" and "&amp;gt;" characters are escaped, and HTML is not rendered. If your JSON is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"welcomeMessage"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;strong&amp;gt;Welcome!&amp;lt;/strong&amp;gt; Here’s your dashboard."&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tag in the DOCX template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{d.welcomeMessage:html}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the welcome message is injected, and the HTML is rendered in the generated document. &lt;/p&gt;

&lt;h3&gt;
  
  
  14. Merge PDFs
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;:appendFile(position)&lt;/strong&gt; formatter lets you dynamically insert a PDF into your generated PDF document. The file can be provided as a Base64 string or a URL in your JSON data. If your JSON data is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"contractPDF"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"base64EncodedPdfFile"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"links"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"welcomePDF"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://domain/welcome.pdf"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tag in the template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{d.links.welcomePDF:appendFile(start)}
{d.contractPDF:appendFile(end)}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  15. Images
&lt;/h3&gt;

&lt;p&gt;To inject images dynamically, a placeholder image must be defined in the template with the tag as alternative text. Then Carbone will replace the placeholder images with images specified in your JSON data-set. &lt;strong&gt;In order you have to:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Insert a placeholder/dummy image in your template.&lt;/li&gt;
&lt;li&gt;Place the tag in the alternative text of the placeholder image.&lt;/li&gt;
&lt;li&gt;Specify the image in your JSON as either a Base64-encoded string or a URL.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If your JSON data is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"logoBase64"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"profilePictureUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://example.com/profile.jpg"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tag in the template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!-- In the alternative text of an image --&amp;gt;
{d.logoBase64}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;will be replaced with the image from your JSON data.&lt;/p&gt;

&lt;h3&gt;
  
  
  16. Charts
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;:chart&lt;/strong&gt; formatter lets you generate charts using &lt;a href="https://echarts.apache.org/en/option.html" rel="noopener noreferrer"&gt;ECharts v5 configuration&lt;/a&gt;. Just Insert a placeholder image in your template (DOCX, ODT, etc.), then the tag must be placed in the alternative text of the placeholder image, and finally, chain the tag with the &lt;code&gt;:chart&lt;/code&gt; formatter. If your JSON data is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "salesChart": {
    "type": "echarts@v5",
    "width": 600,
    "height": 400,
    "option": {
      "xAxis": {
        "type": "category",
        "data": ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
      },
      "yAxis": {
        "type": "value"
      },
      "series": [{
        "data": [150, 230, 224, 218, 135, 147, 260],
        "type": "line"
      }]
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tag in the template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!-- In the alternative text of an image --&amp;gt;
{d.salesChart:chart}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;will render the Echart as SVG image in the generated document.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Important Note: All ECharts configuration options are supported, but external scripts or dependencies are not.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  17. Barcodes
&lt;/h3&gt;

&lt;p&gt;It is possible to insert barcodes into your documents using the &lt;strong&gt;:barcode(type)&lt;/strong&gt; formatter. The barcode is rendered as an SVG image and can be embedded directly into your template. The option &lt;strong&gt;type&lt;/strong&gt; is required to define the format of barcode expected. How to Use:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Define the barcode data in your JSON.&lt;/li&gt;
&lt;li&gt;Insert a placeholder image in your template.&lt;/li&gt;
&lt;li&gt;Place the tag in the alternative text of the placeholder image, chain the &lt;strong&gt;:barcode(type)&lt;/strong&gt; formatter (don't forget the &lt;strong&gt;type&lt;/strong&gt; of barcode as argument).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you JSON is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "productCode": "123456789",
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tag in the template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!-- In the alternative text of an image --&amp;gt;
{d.productCode:barcode(ean13)}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Will inject a barcode image as SVG in the generated document.&lt;/p&gt;

&lt;h3&gt;
  
  
  18. Translations
&lt;/h3&gt;

&lt;p&gt;For multi-language documents, static and dynamic translations are supported using localization dictionaries. During rendering, the language must be provided using the &lt;strong&gt;lang&lt;/strong&gt; option in the report configuration. Both static and dynamic translations rely on the same dictionary.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Static translation&lt;/strong&gt;: use &lt;strong&gt;{t('key')}&lt;/strong&gt; to translate static text in your template. The translation is based on the language set in the report options. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic translation&lt;/strong&gt;: Use the &lt;strong&gt;:t&lt;/strong&gt; formatter to translate dynamic values from your JSON data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your JSON is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"John"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"pending"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;AND if the localization dictionary is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"fr-fr"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; 
    &lt;/span&gt;&lt;span class="nl"&gt;"greeting"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Bonjour"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"pending"&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"En cours"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"en-us"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"greeting"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hello"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"pending"&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"In progress"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tag in the template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{t('greeting')} {d.name} 👋
Payment Status: {d.status:t}.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;will generate the following document if the selected language is &lt;strong&gt;fr&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Bonjour John 👋
Payment Status: En cours.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  19. Hyperlinks
&lt;/h3&gt;

&lt;p&gt;For inserting clickable links in document, insert a hyperlink in your template, and set the URL to a Carbone tag, e.g., &lt;code&gt;{d.documentationUrl}&lt;/code&gt;, that's it. If your JSON is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://carbone.io/documentation"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Documentation"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tag in the template with the hyperlink &lt;code&gt;{d.title.url}&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{d.title.name}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;will render in the document the title "My Profile", and redirect to the page &lt;code&gt;https://carbone.io/documentation&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  20. Electronic Signatures
&lt;/h3&gt;

&lt;p&gt;Two ways are available to inject signatures in documents:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Insert a signature image&lt;/strong&gt;: using dynamic images.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use a third-party e-signature service&lt;/strong&gt;: To do this, prepare your document by placing tags with the &lt;strong&gt;:sign&lt;/strong&gt; formatter where you want signatures to appear. If the JSON is:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"signer"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"John Doe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"john.doe@example.com"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tag in the template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{d.signer:sign}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;will generate a document with the signature position and signer details. This information are used by third-party services like DocuSign, Yousign, Signwell, or Documenso to handle the signature process.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;We’ve covered the most important and commonly used syntax of Carbone's templating. You can now automate the creation of contracts, reports, invoices, and other documents in many fields: finance, healthcare, accounting, legal, and science, more!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Feel free to join our &lt;a href="https://discord.gg/kKB3aPYqnh" rel="noopener noreferrer"&gt;Official Discord&lt;/a&gt; — it’s a friendly place to connect and get help from the Carbone community.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Enjoy creating stunning documents with Carbone! Cheers 🍻&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>beginners</category>
      <category>opensource</category>
      <category>cheatsheet</category>
    </item>
    <item>
      <title>Routage avec RiotJS</title>
      <dc:creator>Steeve</dc:creator>
      <pubDate>Sun, 22 Jun 2025 20:00:00 +0000</pubDate>
      <link>https://forem.com/steeve/routage-avec-riotjs-19a</link>
      <guid>https://forem.com/steeve/routage-avec-riotjs-19a</guid>
      <description>&lt;p&gt;Cet article traite de la création d'une application Riot couplée avec &lt;a href="https://github.com/riot/route" rel="noopener noreferrer"&gt;Riot-Route&lt;/a&gt;, la solution officielle de routage côté client de Riot.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Avant de commencer, assurez-vous d'avoir une application de base RiotJS, ou lisez mes articles précédents.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Le routage côté client lie l'URL du navigateur au contenu de la page. Lorsqu'un utilisateur navigue dans l'application Riot, l'URL change sans demander un nouveau front-end à un serveur. Ceci est appelé une SPA, pour Single Page Applications : Riot gère toutes les mises à jour de données et la navigation sans recharger la page, ce qui rend l'application riche et réactive !&lt;/p&gt;

&lt;p&gt;Créons l'exemple de routage le plus simple ; ensuite, nous explorerons un usage avancé en production.&lt;/p&gt;

&lt;h2&gt;
  
  
  Route de base
&lt;/h2&gt;

&lt;p&gt;Nous visons à créer l'application suivante : un Menu à gauche affichant des liens vers différentes pages, et lorsqu'on clic sur un lien, la section de droite affiche la page correspondante. Le style est alimenté par le CSS Material Design BeerCSS :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyswq2kfk6rfeudzq36ao.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyswq2kfk6rfeudzq36ao.gif" alt="Riot application changing route on Firefox" width="800" height="489"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Écrivez le code suivant dans &lt;strong&gt;./index.riot&lt;/strong&gt;. Le HTML provient de la documentation &lt;a href="https://www.beercss.com/#navigation-drawer" rel="noopener noreferrer"&gt;BeerCSS&lt;/a&gt;, et j'ai ajouté la syntaxe RiotJS pour la logique :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;index-riot&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;router&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;nav&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"drawer left right-round border"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;header&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;nav&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"circle"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"./examples/data/img-card.png"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;h6&amp;gt;&lt;/span&gt;Jon Snow&lt;span class="nt"&gt;&amp;lt;/h6&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/nav&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/header&amp;gt;&lt;/span&gt;
            &lt;span class="c"&gt;&amp;lt;!-- These links will trigger automatically HTML5 history events --&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;i&amp;gt;&lt;/span&gt;inbox&lt;span class="nt"&gt;&amp;lt;/i&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"max"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Inbox&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;b&amp;gt;&lt;/span&gt;24&lt;span class="nt"&gt;&amp;lt;/b&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/favorite"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;i&amp;gt;&lt;/span&gt;favorite&lt;span class="nt"&gt;&amp;lt;/i&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"max"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Starred&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;b&amp;gt;&lt;/span&gt;3&lt;span class="nt"&gt;&amp;lt;/b&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/sent"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;i&amp;gt;&lt;/span&gt;send&lt;span class="nt"&gt;&amp;lt;/i&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"max"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Sent&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;b&amp;gt;&lt;/span&gt;11&lt;span class="nt"&gt;&amp;lt;/b&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"medium-divider"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/subscription"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;i&amp;gt;&lt;/span&gt;rocket&lt;span class="nt"&gt;&amp;lt;/i&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;Subscription&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/settings"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;i&amp;gt;&lt;/span&gt;settings&lt;span class="nt"&gt;&amp;lt;/i&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;Settings&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;

        &lt;span class="nt"&gt;&amp;lt;/nav&amp;gt;&lt;/span&gt;
        &lt;span class="c"&gt;&amp;lt;!-- Your application routes will be rendered here --&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"display:block;margin-left:20px;margin-top:20px"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;route&lt;/span&gt; &lt;span class="na"&gt;path=&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;Inbox&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;/route&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;route&lt;/span&gt; &lt;span class="na"&gt;path=&lt;/span&gt;&lt;span class="s"&gt;"/favorite"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;Starred&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;/route&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;route&lt;/span&gt; &lt;span class="na"&gt;path=&lt;/span&gt;&lt;span class="s"&gt;"/sent"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;Sent&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;/route&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;route&lt;/span&gt; &lt;span class="na"&gt;path=&lt;/span&gt;&lt;span class="s"&gt;"/subscription"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;Subscription&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;/route&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;route&lt;/span&gt; &lt;span class="na"&gt;path=&lt;/span&gt;&lt;span class="s"&gt;"/settings"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;Settings&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;/route&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/router&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
        &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Route&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@riotjs/route&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

        &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;components&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Route&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/index-riot&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Code Source: &lt;a href="https://github.com/steevepay/riot-beercss/blob/main/examples/riot-route/index.basic.riot" rel="noopener noreferrer"&gt;https://github.com/steevepay/riot-beercss/blob/main/examples/riot-route/index.basic.riot&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Cet exemple utilise deux composants fournis par riot-route :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Router&lt;/strong&gt; : Le &lt;code&gt;&amp;lt;router&amp;gt;&lt;/code&gt; enveloppe l'application Riot et détecte automatiquement tous les clics sur les liens qui doivent déclencher un changement de navigation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Route&lt;/strong&gt; : Le &lt;code&gt;&amp;lt;route path="/some/route/:params"&amp;gt;&lt;/code&gt; rend le contenu de la page si l'attribut path correspond au chemin d'URL actuel. Le path peut accepter des expressions régulières (Regex) ou des paramètres, et vous pouvez &lt;u&gt;accéder à la route actuelle&lt;/u&gt; avec l'objet route :
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;route&lt;/span&gt; &lt;span class="na"&gt;path=&lt;/span&gt;&lt;span class="s"&gt;"/:some/:route/:param"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; {JSON.stringify(route.params)} &lt;span class="nt"&gt;&amp;lt;/route&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;route&lt;/span&gt; &lt;span class="na"&gt;path=&lt;/span&gt;&lt;span class="s"&gt;"/search(.*)"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- Assuming the URL is "/search?q=awesome" --&amp;gt;&lt;/span&gt;

  {route.searchParams.get('q')}
&lt;span class="nt"&gt;&amp;lt;/route&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Code Source trouvé sur &lt;a href="https://github.com/riot/route" rel="noopener noreferrer"&gt;Riot-Route&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Pour accéder à la route actuelle dans la section JavaScript, il est possible d'importer l'objet route depuis '@riotjs/route' :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;route&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@riotjs/route&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Route Avancée
&lt;/h2&gt;

&lt;p&gt;Explorons le routage avancé avec les exigences suivantes pour un front-end :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Afficher une page 404 si un chemin d'URL n'existe pas.&lt;/li&gt;
&lt;li&gt;Accéder aux paramètres de requête dans chaque composant de page.&lt;/li&gt;
&lt;li&gt;Pour chaque route, afficher un composant Riot en tant que page.&lt;/li&gt;
&lt;li&gt;Créer un fichier de configuration de routage définissant toutes les routes, chemins et composants.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffxnepfn2ql0kzfm69hgr.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffxnepfn2ql0kzfm69hgr.gif" alt="Riot application on Google Chrome with a routing showing 404 when the page does not exist" width="760" height="402"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Dans un premier temps, nous allons créer 6 composants, un pour chaque page et un autre pour la page 404 Not Found. Les composants sont situés dans le répertoire &lt;strong&gt;pages&lt;/strong&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;pages/p-favorite.riot&lt;/span&gt;
&lt;span class="s"&gt;pages/p-inbox.riot&lt;/span&gt;
&lt;span class="s"&gt;pages/p-sent.riot&lt;/span&gt;
&lt;span class="s"&gt;pages/p-settings.riot&lt;/span&gt;
&lt;span class="s"&gt;pages/p-subscription.riot&lt;/span&gt;
&lt;span class="s"&gt;pages/p-not-found.riot&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Chaque composant possède une seule balise de titre &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt;, par exemple, le composant &lt;strong&gt;pages/p-sent.riot&lt;/strong&gt; ressemble à ceci :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;p-sent&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;Sent&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/p-sent&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ou le composant &lt;strong&gt;pages/p-not-found.riot&lt;/strong&gt; ressemble à ceci :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;p-not-found&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt; 404 Page Not Found &lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/p-not-found&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ensuite, créez un fichier de configuration de routage global dans &lt;strong&gt;routes.js&lt;/strong&gt;. Le fichier renvoie une liste de pages, et chaque page possède un nom (name), un chemin avec une expression régulière longue (path), et un composant correspondant (component):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;     &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Inbox&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;href&lt;/span&gt;     &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;path&lt;/span&gt;     &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/(/?[?#].*)?(#.*)?&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;p-inbox&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;icon&lt;/span&gt;     &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;inbox&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;     &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Starred&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;href&lt;/span&gt;     &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/favorite&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;path&lt;/span&gt;     &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/favorite(/?[?#].*)?(#.*)?&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;p-favorite&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;icon&lt;/span&gt;     &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;favorite&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;     &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Sent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;href&lt;/span&gt;     &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/sent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;path&lt;/span&gt;     &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/sent(/?[?#].*)?(#.*)?&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;p-sent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;icon&lt;/span&gt;     &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;send&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;separator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;     &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Subscription&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;href&lt;/span&gt;     &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/subscription&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;path&lt;/span&gt;     &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/subscription(/?[?#].*)?(#.*)?&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;p-subscription&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;icon&lt;/span&gt;     &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rocket&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;     &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Settings&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;href&lt;/span&gt;     &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/settings&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;path&lt;/span&gt;     &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/settings(/?[?#].*)?(#.*)?&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;p-settings&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;icon&lt;/span&gt;     &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;settings&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Source code: &lt;a href="https://github.com/steevepay/riot-beercss/blob/main/examples/riot-route/routes.js" rel="noopener noreferrer"&gt;https://github.com/steevepay/riot-beercss/blob/main/examples/riot-route/routes.js&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Le composant &lt;code&gt;&amp;lt;route&amp;gt;&lt;/code&gt; de Riot utilisera l'attribut &lt;code&gt;path&lt;/code&gt;. Chaque expression régulière est composée de 3 parties :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;/settings&lt;/code&gt; : Chemin de la page (chaîne statique requise)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;(/?[?#].*)&lt;/code&gt; : Paramètres de requête (groupe facultatif)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;(#.*)?&lt;/code&gt; : Fragment, une section au sein d'une page (groupe facultatif)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Maintenant, importez &lt;strong&gt;routes.js&lt;/strong&gt; et tous les composants dans le fichier &lt;strong&gt;index.riot&lt;/strong&gt; : Définissez les composants dans l'objet Riot &lt;code&gt;components:{}&lt;/code&gt;, et chargez les routes dans l'objet &lt;code&gt;state:{}&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;index-riot&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;router&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;nav&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"drawer left right-round border"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;header&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;nav&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"circle"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"./examples/data/img-card.png"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;h6&amp;gt;&lt;/span&gt;Jon Snow&lt;span class="nt"&gt;&amp;lt;/h6&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/nav&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/header&amp;gt;&lt;/span&gt;
            &lt;span class="c"&gt;&amp;lt;!-- Navigation bar created dynamically --&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;each=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;page&lt;/span&gt; &lt;span class="na"&gt;in&lt;/span&gt; &lt;span class="na"&gt;state.pages&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;page.href&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;i&amp;gt;&lt;/span&gt;{ page.icon }&lt;span class="nt"&gt;&amp;lt;/i&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"max"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{ page.name }&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;if=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;page.separator =&lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt; &lt;span class="na"&gt;true&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"medium-divider"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;            
        &lt;span class="nt"&gt;&amp;lt;/nav&amp;gt;&lt;/span&gt;
        &lt;span class="c"&gt;&amp;lt;!-- Your application components/routes will be rendered here --&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"display:block;margin-left:20px;margin-top:20px"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;route&lt;/span&gt; &lt;span class="na"&gt;each=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;page&lt;/span&gt; &lt;span class="na"&gt;in&lt;/span&gt; &lt;span class="na"&gt;state.pages&lt;/span&gt;  &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;path=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;page.path&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;is=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;page.component&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;route=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;route&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/route&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;p-not-found&lt;/span&gt; &lt;span class="na"&gt;if=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;state.showNotFound&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/router&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
        &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;toRegexp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;match&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@riotjs/route&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;pages&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./routes.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

        &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;pInbox&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./pages/p-inbox.riot&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;pFavorite&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./pages/p-favorite.riot&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;pSent&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./pages/p-sent.riot&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;pSettings&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./pages/p-settings.riot&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;pSubscription&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./pages/p-subscription.riot&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;pNotFound&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./pages/p-not-found.riot&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

        &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;components&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pInbox&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pFavorite&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pSent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pSettings&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pSubscription&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pNotFound&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;pages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;showNotFound&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="nf"&gt;onMounted &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// ROUTING: create a stream on all routes&lt;/span&gt;
                &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;anyRouteStream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;(.*)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="c1"&gt;// ROUTING: check any route change to understand if the not found site should be displayed&lt;/span&gt;
                &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;anyRouteStream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;value&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;showNotFound&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pathname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;toRegexp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;  
                &lt;span class="p"&gt;})&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="nf"&gt;onUnmounted&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;anyRouteStream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/index-riot&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Code Source: &lt;a href="https://github.com/steevepay/riot-beercss/blob/main/examples/riot-route/index.advanced.riot" rel="noopener noreferrer"&gt;https://github.com/steevepay/riot-beercss/blob/main/examples/riot-route/index.advanced.riot&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ce code diffère beaucoup de l'exemple de base ; voici les principaux changements :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pour imprimer un composant pour chaque page, une boucle est créée sur &lt;code&gt;state.pages&lt;/code&gt;. Au sein de chaque &lt;code&gt;&amp;lt;route&amp;gt;&amp;lt;/route&amp;gt;&lt;/code&gt;, les éléments HTML span sont utilisés comme composants Riot en ajoutant l'attribut &lt;code&gt;is&lt;/code&gt; :
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;route&lt;/span&gt; &lt;span class="na"&gt;each=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;page&lt;/span&gt; &lt;span class="na"&gt;in&lt;/span&gt; &lt;span class="na"&gt;state.pages&lt;/span&gt;  &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;path=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;page.path&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;is=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;page.component&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;route=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;route&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/route&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Les liens du menu sont également générés grâce à la configuration de route, accessible avec &lt;code&gt;state.pages&lt;/code&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;each=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;page&lt;/span&gt; &lt;span class="na"&gt;in&lt;/span&gt; &lt;span class="na"&gt;state.pages&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;page.href&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;i&amp;gt;&lt;/span&gt;{ page.icon }&lt;span class="nt"&gt;&amp;lt;/i&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"max"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{ page.name }&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;if=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;page.separator =&lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt; &lt;span class="na"&gt;true&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"medium-divider"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;L'objet &lt;code&gt;route&lt;/code&gt; est utilisé dans la partie JavaScript pour vérifier si l'URL actuelle existe : Un Stream de routes est créé pour écouter les changements de route dans le &lt;code&gt;onMounted () {}&lt;/code&gt; hook (cycle de vie Riot). Lorsqu'une route change, une fonction vérifie si l'URL correspond à une route existante :
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;onMounted &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;anyRouteStream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;(.*)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;anyRouteStream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;value&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;showNotFound&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pathname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;toRegexp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;  
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="nf"&gt;onUnmounted&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// When the component is unmounted, the stream is stopped.&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;anyRouteStream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Pour chaque composant, la route actuelle est passée en tant que &lt;a href="https://riot.js.org/documentation/#properties" rel="noopener noreferrer"&gt;Props&lt;/a&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;component&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;route&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/span&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Au sein de chaque composant, la route est accessible avec &lt;code&gt;props.route&lt;/code&gt;, par exemple dans le fichier &lt;strong&gt;c-inbox.riot&lt;/strong&gt; :
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;p-inbox&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt; Inbox &lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;Filter: { props.route.searchParams.get('filter') }&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;Order By: { props.route.searchParams.get('order') }&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/p-inbox&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Vous pouvez maintenant utiliser les paramètres de requête pour demander une API lorsque la page est chargée dans le &lt;code&gt;onMounted(){}&lt;/code&gt; hook (cycle de vie Riot).&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Riot Route vous permet de créer la navigation facilement, avec une syntaxe toujours proche des standards HTML.&lt;/p&gt;

&lt;p&gt;Une limitation des applications monopages est qu'elles dépendent d'un backend/API pour charger les données. Le navigateur/utilisateur doit attendre que le contenu soit rendu. Pour contrer ce problème, vous pouvez rendre le HTML côté serveur avec &lt;a href="https://github.com/riot/ssr" rel="noopener noreferrer"&gt;Riot-SSR&lt;/a&gt; : la requête reçoit la page directement remplie de données.&lt;/p&gt;

&lt;p&gt;Passez une excellente journée ! Santé 🍻&lt;/p&gt;

</description>
      <category>riotjs</category>
      <category>french</category>
      <category>frontend</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Partage de données entre composants Riot avec Riot-Meiosis (State Manager)</title>
      <dc:creator>Steeve</dc:creator>
      <pubDate>Mon, 16 Jun 2025 12:00:00 +0000</pubDate>
      <link>https://forem.com/steeve/partage-de-donnees-entre-composants-riot-avec-riot-meiosis-state-manager-2oi</link>
      <guid>https://forem.com/steeve/partage-de-donnees-entre-composants-riot-avec-riot-meiosis-state-manager-2oi</guid>
      <description>&lt;p&gt;Cet article explique comment créer un gestionnaire d'état (state manager) pour partager des données entre plusieurs composants RiotJS.&lt;/p&gt;

&lt;p&gt;Avant de commencer, assurez-vous d'avoir une application de base Riot, ou lisez mes articles précédents. Je suppose que vous avez une compréhension fondamentale de Riot ; cependant, n'hésitez pas à vous référer à la documentation si nécessaire : &lt;a href="https://riot.js.org/documentation/" rel="noopener noreferrer"&gt;https://riot.js.org/documentation/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Il existe trois méthodes pour partager des données entre composants :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Utiliser les propriétés Riot (props) pour passer des valeurs à un composant enfant. Le composant enfant doit émettre des événements vers le composant parent si une action se produit, comme un clic ou un changement d'entrée. Dans ce cas, la portée de communication est limitée : du composant parent vers l'enfant et de l'enfant vers le parent.&lt;/li&gt;
&lt;li&gt;Utiliser un émetteur d'événements comme Mitt, un modèle de messagerie appelé Pub/Sub, en savoir plus dans mon article précédent.&lt;/li&gt;
&lt;li&gt;Dernière méthode : un gestionnaire d'état : Un état global partagé et accessible par tous les composants. Dans d'autres frameworks frontaux, vous avez peut-être entendu parler de Pinia pour Vuejs ou Redux pour React. Pour RiotJS, le gestionnaire d'état est riot-meiosis.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://meiosis.js.org" rel="noopener noreferrer"&gt;Meiosis&lt;/a&gt; est un modèle de gestionnaire d'état utilisant des flux (streams) pour communiquer des valeurs, avec le principe de rendre l'utilisation très simple. Extrait de la documentation Meiosis :&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;L'idée est d'avoir un objet unique, de niveau supérieur, qui représente l'état de votre application, et d'avoir une manière simple de mettre à jour cet état. Les vues sont rendues en fonction de l'état et déclenchent des actions pour mettre à jour l'état. C'est tout !&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://github.com/riot-tools/meiosis#readme" rel="noopener noreferrer"&gt;Riot-meiosis&lt;/a&gt; reproduit ce modèle et est dédié à RiotJS. Cet article montre comment l'utiliser. L'objectif est de :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Étape 1 : Créer un gestionnaire d'état global&lt;/li&gt;
&lt;li&gt;Étape 2 : Sur la page d'accueil de l'application Riot, afficher une carte accueillant une personne avec son prénom et son nom.&lt;/li&gt;
&lt;li&gt;Étape 3 : Afficher un dialogue pour modifier le prénom et le nom.&lt;/li&gt;
&lt;li&gt;Étape 4 : Sauvegarder les nouvelles valeurs dans l'état global&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1yqqythbdk1e6izl6uv1.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1yqqythbdk1e6izl6uv1.gif" alt="Riot application using a Global state manager, two components are sharing data" width="600" height="403"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuration de Riot Meiosis
&lt;/h2&gt;

&lt;p&gt;Commencez par installer le package NPM dans votre projet Riot/Vite :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i &lt;span class="nt"&gt;--save&lt;/span&gt; @riot-tools/meiosis
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ensuite, créez un fichier &lt;strong&gt;store.js&lt;/strong&gt;, qui sera l'état global :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;RiotMeiosis&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@riot-tools/meiosis&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;firstname&lt;/span&gt;     &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Jon&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;lastname&lt;/span&gt;      &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Snow&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;firstnameEdit&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;lastnameEdit&lt;/span&gt;  &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;displayForm&lt;/span&gt;   &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cm"&gt;/** Create the state manager instance */&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stateManager&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RiotMeiosis&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;flushOnRead&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;statesToKeep&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="cm"&gt;/** Extract the state stream **/&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;stream&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;stateManager&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cm"&gt;/** Add Root state reducer: merge the old and new state objects */&lt;/span&gt;
&lt;span class="nx"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addReducer&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;newState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;oldState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Object oldState { firstname: "John", lastname: "Wick", firstnameEdit: "", lastnameEdit: "", email: "", displayForm: false } &lt;/span&gt;
    &lt;span class="c1"&gt;// Object newState { displayForm: true }&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;oldState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;newState&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="cm"&gt;/** Simplifying the connect function for components */&lt;/span&gt;
    &lt;span class="na"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;stateManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;globalState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ownState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;ownState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;globalState&lt;/span&gt; &lt;span class="p"&gt;}))(&lt;/span&gt;&lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="cm"&gt;/** Provides the dispatch function to update values */&lt;/span&gt;
    &lt;span class="na"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;stateManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dispatch&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Code Source: &lt;a href="https://github.com/steevepay/riot-beercss/blob/main/examples/meiosis/store.js" rel="noopener noreferrer"&gt;https://github.com/steevepay/riot-beercss/blob/main/examples/meiosis/store.js&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Détails du code :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Un réducteur est créé pour fusionner l'état global avec les nouvelles valeurs provenant de tous les composants.&lt;/li&gt;
&lt;li&gt;Pour connecter le composant à l'état global, le composant Riot doit être enveloppé avec la fonction &lt;code&gt;store.connect()&lt;/code&gt;, et passer un &lt;u&gt;composant&lt;/u&gt; et une &lt;u&gt;fonction de fusion&lt;/u&gt; comme argument : cela fusionnera l'état du composant avec l'état global. Pour chaque composant, l'état global est accessible avec l'expression &lt;code&gt;this.state.value&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Le store renvoie la &lt;code&gt;connexion&lt;/code&gt; et la fonction &lt;code&gt;dispatch&lt;/code&gt; utilisée pour mettre à jour les valeurs.&lt;/li&gt;
&lt;li&gt;L'état global est initialisé avec un prénom et nom, un second prénom et nom pour les entrées du dialogue afin de modifier le profil, et un booléen &lt;code&gt;displayForm&lt;/code&gt; pour afficher le dialogue.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Écrivez le code HTML dans &lt;strong&gt;c-welcome-card.riot&lt;/strong&gt;, et connectez le Store au composant:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;c-welcome-card&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;article&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"no-padding border round"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"responsive small top-round"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"./examples/data/img-card.png"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"padding"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;h5&amp;gt;&lt;/span&gt;Welcome&lt;span class="nt"&gt;&amp;lt;/h5&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Bonjour &lt;span class="nt"&gt;&amp;lt;b&amp;gt;&lt;/span&gt;{ state.firstname} { state.lastname }&lt;span class="nt"&gt;&amp;lt;/b&amp;gt;&lt;/span&gt; 👋 to our app! We're excited to have you here.Whether you're in finance, marketing, or operations, our app delivers the insights you need to drive growth and stay ahead of the competition.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;nav&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;editProfile&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Edit Profile&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/nav&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/article&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
        &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./store.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="nf"&gt;editProfile &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; 
                    &lt;span class="na"&gt;displayForm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;firstnameEdit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;firstname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;lastnameEdit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lastname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="p"&gt;})&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/c-welcome-card&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Code Source: &lt;a href="https://github.com/steevepay/riot-beercss/blob/main/examples/meiosis/c-welcome-card.riot" rel="noopener noreferrer"&gt;https://github.com/steevepay/riot-beercss/blob/main/examples/meiosis/c-welcome-card.riot&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Détails du code :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Le Store est chargé, et le composant est connecté avec &lt;code&gt;store.connect()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Pour mettre à jour l'une des valeurs du magasin global, appelez la fonction &lt;code&gt;store.dispatch()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Lorsque le bouton est cliqué, la fonction &lt;code&gt;editProfile()&lt;/code&gt; est déclenchée pour afficher le dialogue et définir &lt;code&gt;firstnameEdit&lt;/code&gt; et &lt;code&gt;lastnameEdit&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Créez un fichier nommé &lt;strong&gt;c-form.riot&lt;/strong&gt;, et connectez le Store pour accéder aux valeurs &lt;code&gt;firstnameEdit&lt;/code&gt; et &lt;code&gt;lastnameEdit&lt;/code&gt;. Il sera utilisé pour les inputs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;c-form&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;c-dialog&lt;/span&gt; &lt;span class="na"&gt;active=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt;  &lt;span class="na"&gt;state.displayForm&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;oncancel=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;close&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onconfirm=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;confirmEdit&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;slot=&lt;/span&gt;&lt;span class="s"&gt;"body"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;h5&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"margin-bottom:30px"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Edit Profile&lt;span class="nt"&gt;&amp;lt;/h5&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;c-input&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;state.firstnameEdit&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onkeyup=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;(ev) =&lt;/span&gt;&lt;span class="err"&gt;&amp;gt; &lt;/span&gt;&lt;span class="s"&gt;updateInput(ev,&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="na"&gt;firstnameEdit&lt;/span&gt;&lt;span class="err"&gt;')&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onchange=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;(ev) =&lt;/span&gt;&lt;span class="err"&gt;&amp;gt; &lt;/span&gt;&lt;span class="s"&gt;updateInput(ev,&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="na"&gt;firstnameEdit&lt;/span&gt;&lt;span class="err"&gt;')&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;outlined=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;round=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Firstname"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;c-input&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;state.lastnameEdit&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onkeyup=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;(ev) =&lt;/span&gt;&lt;span class="err"&gt;&amp;gt; &lt;/span&gt;&lt;span class="s"&gt;updateInput(ev,&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="na"&gt;lastnameEdit&lt;/span&gt;&lt;span class="err"&gt;')&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onchange=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;(ev) =&lt;/span&gt;&lt;span class="err"&gt;&amp;gt; &lt;/span&gt;&lt;span class="s"&gt;updateInput(ev,&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="na"&gt;lastnameEdit&lt;/span&gt;&lt;span class="err"&gt;')&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;  &lt;span class="na"&gt;outlined=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;round=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Lastname"&lt;/span&gt;  &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/c-dialog&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
        &lt;span class="cm"&gt;/** State manager **/&lt;/span&gt;
        &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./store.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="cm"&gt;/** Components **/&lt;/span&gt;
        &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;cInput&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../../components/c-input.riot&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;cButton&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../../components/c-button.riot&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;cDialog&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../../components/c-dialog.riot&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;components&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;cInput&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nx"&gt;cButton&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nx"&gt;cDialog&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;displayForm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="nf"&gt;updateInput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;keyName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;keyName&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="nf"&gt;confirmEdit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; 
                    &lt;span class="na"&gt;displayForm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                    &lt;span class="na"&gt;firstname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;firstnameEdit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;lastname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lastnameEdit&lt;/span&gt;
                &lt;span class="p"&gt;})&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/c-form&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Code Source: &lt;a href="https://github.com/steevepay/riot-beercss/blob/main/examples/meiosis/c-form.riot" rel="noopener noreferrer"&gt;https://github.com/steevepay/riot-beercss/blob/main/examples/meiosis/c-form.riot&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Détails du code :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Trois composants personnalisés sont chargés : un Input, un Dialog, et un bouton.&lt;/li&gt;
&lt;li&gt;Le dialogue affiche deux composants d'entrée pour mettre à jour &lt;code&gt;firstnameEdit&lt;/code&gt; et &lt;code&gt;lastnameEdit&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Si le bouton confirmer est cliqué, les nouvelles valeurs sont sauvegardées dans l'état global firstname et lastname grâce à la fonction &lt;code&gt;store.dispatch&lt;/code&gt;. La carte de bienvenue reçoit la mise à jour ; le prénom et le nom sont rafraîchis.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;Pourquoi utiliser firstnameEdit/lastnameEdit et non directement firstname/lastname ? Lorsqu'un utilisateur saisit de nouveaux noms, il peut annuler à tout moment l'édition sans affecter firstname/lastname. Le changement de valeur ne prend effet que lorsqu'un bouton confirmer est cliqué.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Maintenant, nous pouvons charger les deux composants dans un fichier commun &lt;strong&gt;index.riot&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;index-riot&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"width:400px;padding:40px;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;c-welcome-card&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;c-form&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;

        &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;cForm&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./c-form.riot&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;cWelcomeCard&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./c-welcome-card.riot&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

        &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;components&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;cForm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nx"&gt;cWelcomeCard&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/index-riot&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Code Source: &lt;a href="https://github.com/steevepay/riot-beercss/blob/main/examples/meiosis/index.riot" rel="noopener noreferrer"&gt;https://github.com/steevepay/riot-beercss/blob/main/examples/meiosis/index.riot&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Les deux composants sont indépendants, ne communiquant que par le gestionnaire d'état global.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Un gestionnaire d'état est très puissant pour lire et mettre à jour des données entre les composants Riot. Les données peuvent être des listes, des objets ou des cartes. Le magasin peut être connecté à un nombre illimité de composants pour de grandes applications frontales de production réalisées avec RiotJS !&lt;/p&gt;

</description>
      <category>riotjs</category>
      <category>french</category>
      <category>javascript</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Partage de données entre composants RiotJS avec Mitt (émetteur d'évènements)</title>
      <dc:creator>Steeve</dc:creator>
      <pubDate>Mon, 09 Jun 2025 12:00:00 +0000</pubDate>
      <link>https://forem.com/steeve/partage-de-donnees-entre-composants-riotjs-avec-mitt-emetteur-devenements-31di</link>
      <guid>https://forem.com/steeve/partage-de-donnees-entre-composants-riotjs-avec-mitt-emetteur-devenements-31di</guid>
      <description>&lt;p&gt;Cet article traite de l'utilisation des événements avec Mitt entre plusieurs composants Riot pour partager des données.&lt;/p&gt;

&lt;p&gt;Avant de commencer, assurez-vous d'avoir une application de base RiotJS, ou lisez mes articles précédents.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Je suppose que vous avez une compréhension fondamentale de Riot ; cependant, n'hésitez pas à vous référer à la documentation si nécessaire : &lt;a href="https://riot.js.org/documentation/" rel="noopener noreferrer"&gt;https://riot.js.org/documentation/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Il existe trois méthodes pour partager des données entre composants :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Utiliser les propriétés Riot &lt;a href="https://riot.js.org/documentation/#properties" rel="noopener noreferrer"&gt;props&lt;/a&gt; pour passer des valeurs à un composant enfant. Le composant enfant doit émettre des événements vers le composant parent si une action se produit, comme un clic ou un changement d'entrée. &lt;strong&gt;Dans ce cas, la portée de communication est limitée&lt;/strong&gt;: du composant parent vers l'enfant et de l'enfant vers le parent.&lt;/li&gt;
&lt;li&gt;Utiliser un gestionnaire d'état (state manager), comme Pinia pour Vuejs ou Redux pour React, pour partager un état entre les composants/pages. &lt;strong&gt;La portée de communication est globale&lt;/strong&gt;: tous les composants peuvent voir et modifier les états.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;La dernière méthode utilise un émetteur d'événements comme Mitt, un modèle de messagerie appelé Pub/Sub : un ou plusieurs &lt;u&gt;éditeurs&lt;/u&gt; émettent les données, et &lt;u&gt;les abonnés&lt;/u&gt; les traite sans savoir quels sont les éditeurs. Cet article reproduit le modèle entre plusieurs composants RiotJS ! L'objectif est de :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Étape 1 : Créer une application Riot de base affichant un composant Modal de Confirmation lors du clic sur un bouton. Le bouton est l'éditeur, et le Modal est l'abonné.&lt;/li&gt;
&lt;li&gt;Étape 2 : Lorsque le modal est visible et soit validé soit annulé, il émet un événement vers l'éditeur d'origine. Dans ce cas, le Modal est l'éditeur, et le Bouton est l'abonné.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7994ebpc1hekdrwrw1xd.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7994ebpc1hekdrwrw1xd.gif" alt="Animation of a Riot confirmation modal opening due to a Mitt event" width="760" height="348"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Base de l'émetteur
&lt;/h2&gt;

&lt;p&gt;Commencez par installer &lt;a href="https://www.npmjs.com/package/mitt" rel="noopener noreferrer"&gt;Mitt&lt;/a&gt; dans votre projet Riot/Vite :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;mitt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Créez un fichier nommé &lt;strong&gt;events.js&lt;/strong&gt;, puis chargez Mitt et instanciez-le :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/** EVENT BUS **/&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;mitt&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mitt&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;_bus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;mitt&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;_bus&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Composant de Dialogue (Abonné)
&lt;/h2&gt;

&lt;p&gt;Créez un composant de dialogue nommé &lt;strong&gt;c-dialog.riot&lt;/strong&gt;. La base du composant est tirée de mon article précédent &lt;a href="https://dev.to/steeve/composant-dialogue-avec-riotjs-dne"&gt;Créer un composant de dialogue avec RiotJS&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;c-dialog&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;dialog&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"{state.active ? 'active ' : null}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;h5&amp;gt;&lt;/span&gt;{ state.title }&lt;span class="nt"&gt;&amp;lt;/h5&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
            { state.message }
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;nav&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"right-align no-space"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;toggleModal&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"transparent link"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{ state.cancel }&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;validateAction&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"transparent link"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{ state.validate }&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/nav&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/dialog&amp;gt;&lt;/span&gt;
       &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
       &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;events&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./events.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

        &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Confirmation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Are you sure?&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;callbackID&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;args&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;validate&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Validate&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;cancel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Cancel&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="nf"&gt;onMounted&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;open-modal-validation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;openModalValidation&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="nf"&gt;onUnmounted&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;off&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;open-modal-validation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;openModalValidation&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="nf"&gt;validateAction &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;callbackID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;callbackID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toggleModal&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="nf"&gt;openModalValidation &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callbackID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                    &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="nx"&gt;callbackID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
                &lt;span class="p"&gt;})&lt;/span&gt;
                &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toggleModal&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="nf"&gt;toggleModal&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;active&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
                &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;active&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Modal opened.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Modal closed.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/c-dialog&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Code Source: &lt;a href="https://github.com/steevepay/riot-beercss/blob/main/examples/mitt/c-dialog.riot" rel="noopener noreferrer"&gt;https://github.com/steevepay/riot-beercss/blob/main/examples/mitt/c-dialog.riot&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Détails du code :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Le modal est visible uniquement si &lt;code&gt;state.active&lt;/code&gt; est &lt;code&gt;true&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Le dialogue peut être personnalisé avec des données personnalisées, stockées dans l'objet &lt;a href="https://riot.js.org/documentation/#state" rel="noopener noreferrer"&gt;State&lt;/a&gt; Riot.&lt;/li&gt;
&lt;li&gt;Le bus d'événements est chargé avec &lt;code&gt;import events from './events.js'&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Lorsque le composant est monté, il s'abonne à l'événement &lt;code&gt;open-modal-validation&lt;/code&gt; grâce à &lt;code&gt;events.on('open-modal-validation', this.openModalValidation);&lt;/code&gt;. Lorsque l'événement nommé &lt;code&gt;open-modal-validation&lt;/code&gt; se produit, il exécute la fonction &lt;code&gt;openModalValidation&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;La fonction &lt;code&gt;openModalValidation&lt;/code&gt; bascule la visibilité du modal en définissant &lt;code&gt;state.active&lt;/code&gt; sur true. En même temps, elle recueille des données supplémentaires telles qu'un state.message personnalisé et un &lt;code&gt;state.callbackID&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Si le bouton de validation est cliqué, il émet un événement vers &lt;code&gt;state.callback&lt;/code&gt; avec des arguments personnalisés &lt;code&gt;state.args&lt;/code&gt; ; cela peut être un objet ou une chaîne de caractères.&lt;/li&gt;
&lt;li&gt;Si le bouton d'annulation est cliqué, le modal est désactivé en définissant &lt;code&gt;state.active&lt;/code&gt; sur &lt;code&gt;false&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Composant Index (Éditeur)
&lt;/h2&gt;

&lt;p&gt;Enfin, chargez le Dialogue et un Bouton dans un fichier &lt;strong&gt;index.riot&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;index-riot&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"width:600px;padding:20px;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;c-dialog&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;c-button&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;confirmDeletion&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; Delete File &lt;span class="nt"&gt;&amp;lt;/c-button&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
        &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;cButton&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../../components/c-button.riot&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;cSnackbar&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../../components/c-snackbar.riot&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;cDialog&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./c-dialog.riot&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;events&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./events.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

        &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;components&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;cButton&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nx"&gt;cDialog&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="nf"&gt;onMounted&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;delete-file&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;deleteFile&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="nf"&gt;onUnmounted&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;off&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;delete-file&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;deleteFile&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="nf"&gt;confirmDeletion &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;open-modal-validation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
                    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Do you confirm you want to delete the file &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;2024-04-invoice.pdf&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;callbackID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;delete-file&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
                &lt;span class="p"&gt;});&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="nf"&gt;deleteFile &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;FILE DELETED! 🗑️&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/index-riot&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Code Source: &lt;a href="https://github.com/steevepay/riot-beercss/blob/main/examples/mitt/index.riot" rel="noopener noreferrer"&gt;https://github.com/steevepay/riot-beercss/blob/main/examples/mitt/index.riot&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Détails du code :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Les composants sont importés avec &lt;code&gt;import cDialog from "./components/c-dialog.riot";&lt;/code&gt; puis chargés dans l'objet Riot &lt;code&gt;components:{}&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Le composant dialog est instancié avec  dans le HTML.&lt;/li&gt;
&lt;li&gt;L'émetteur d'événements, Mitt, est chargé avec import events from "./events.js".&lt;/li&gt;
&lt;li&gt;Lors du clic sur le bouton, la fonction confirmDeletion est exécutée et émet l'événement "open-modal-validation". Le Dialogue est maintenant visible ! Simultanément, un message personnalisé et l'ID de l'abonné "delete-file" sont passés en tant qu'arguments pour l'événement.&lt;/li&gt;
&lt;li&gt;Lorsque le bouton du dialogue est cliqué, un événement est émis, en utilisant &lt;code&gt;state.callbackID&lt;/code&gt; comme destinataire de l'abonné.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Cette méthode peut être étendue en créant plus de boutons (éditeurs) émettant vers un seul Dialogue (abonné), par exemple :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyfbmtorlvaa7421od24t.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyfbmtorlvaa7421od24t.gif" alt="Three buttons are opening the same Dialog box to confirm deletions actions, either: a file, a bucket or an account" width="760" height="310"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Voici le code de index.riot pour reproduire la démo GIF :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;index-riot&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"width:600px;padding:50px;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;c-dialog&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;c-button&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;confirmDeletion&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; Delete File &lt;span class="nt"&gt;&amp;lt;/c-button&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;c-button&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;confirmDeletionBucket&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; Delete Bucket &lt;span class="nt"&gt;&amp;lt;/c-button&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;c-button&lt;/span&gt; &lt;span class="na"&gt;error=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;true&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;confirmDeletionAccount&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; Delete Account &lt;span class="nt"&gt;&amp;lt;/c-button&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
        &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;cButton&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../../components/c-button.riot&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;cSnackbar&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../../components/c-snackbar.riot&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;cDialog&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./c-dialog.riot&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;events&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./events.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

        &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;components&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;cButton&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nx"&gt;cDialog&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="nf"&gt;onMounted&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;delete-file&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;deleteFile&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;delete-bucket&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;deleteBucket&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;delete-account&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;deleteAccount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="nf"&gt;onUnmounted&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;off&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;delete-file&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;deleteFile&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;off&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;delete-bucket&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;deleteBucket&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;off&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;delete-account&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;deleteAccount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="nf"&gt;getRandomNumber&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="nf"&gt;confirmDeletion &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;open-modal-validation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
                    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Do you confirm you want to delete the File &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;2024-04-invoice.pdf&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;callbackID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;delete-file&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;file-&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getRandomNumber&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="p"&gt;});&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="nf"&gt;confirmDeletionBucket&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;open-modal-validation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
                    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Are you sure you want to delete this S3 bucket &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;2024-assets&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;? This action is irreversible.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;callbackID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;delete-bucket&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bucket-&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getRandomNumber&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="p"&gt;});&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="nf"&gt;confirmDeletionAccount&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;open-modal-validation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
                    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Are you sure you want to proceed with deleting your account? This action is irreversible and will permanently remove all your personal data associated with the account.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;callbackID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;delete-account&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;account-&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getRandomNumber&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="p"&gt;});&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="nf"&gt;deleteFile &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;%c File deleted! ID: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;background: #222; color: #bada55&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="nf"&gt;deleteBucket &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;%c Bucket deleted! ID: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;background: #222; color: #ff00ff&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="nf"&gt;deleteAccount &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;%c Account deleted! ID: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;background: #222; color: #ff0000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/index-riot&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Code Source: &lt;a href="https://github.com/steevepay/riot-beercss/blob/main/examples/mitt/index.riot" rel="noopener noreferrer"&gt;https://github.com/steevepay/riot-beercss/blob/main/examples/mitt/index.riot&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Détails du code :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Dans le &lt;a href="https://riot.js.org/api/#component-object" rel="noopener noreferrer"&gt;onMounted&lt;/a&gt; Riot Hook, trois événements sont écoutés et redirigés vers trois fonctions : &lt;code&gt;deleteFile&lt;/code&gt;, &lt;code&gt;deleteBucket&lt;/code&gt; ou &lt;code&gt;deleteAccount&lt;/code&gt;. Dans une application de production, cela pourrait être un appel API pour supprimer une ressource (fichier ou élément dans une base de données).&lt;/li&gt;
&lt;li&gt;Trois boutons sont créés dans le HTML, et chaque clic émet l'événement &lt;code&gt;open-modal-validation&lt;/code&gt; et passe un message personnalisé, un ID de rappel et un argument :

&lt;ul&gt;
&lt;li&gt;Le &lt;code&gt;callbackID&lt;/code&gt; est un événement à émettre lorsque le bouton de validation est cliqué.&lt;/li&gt;
&lt;li&gt;Les &lt;code&gt;args&lt;/code&gt; sont utilisés pour passer un ID de ressource d'une API ou d'une base de données, comme un ID de fichier ou un ID de compte. Dans notre cas, un ID aléatoire est passé en tant qu'argument.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Lorsque qu'un bouton du composant Dialogue est validé, il émet &lt;code&gt;callbackID&lt;/code&gt; en tant qu'événement, et la fonction correspondante est exécutée pour supprimer le fichier, le bucket ou le compte.&lt;/li&gt;
&lt;li&gt;Lorsque le composant est retiré de la page web, tout événement doit être écouté : Lorsque le onUnmounted](&lt;a href="https://riot.js.org/api/#component-object" rel="noopener noreferrer"&gt;https://riot.js.org/api/#component-object&lt;/a&gt;) Riot hook est exécuté, &lt;code&gt;event.off&lt;/code&gt; supprime l'abonnement à l'événement.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Au lieu de créer un Dialogue pour chaque bouton, un seul Dialogue suffit pour plusieurs boutons avec le modèle pub/sub. Maintenant, un composant peut écouter et émettre des événements pour communiquer des données basées sur des actions. Voilà 🎉&lt;/p&gt;

&lt;p&gt;Passez une excellente journée ! Santé 🍻&lt;/p&gt;

</description>
      <category>riotjs</category>
      <category>french</category>
      <category>frontend</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Composant Stepper avec RiotJS</title>
      <dc:creator>Steeve</dc:creator>
      <pubDate>Mon, 02 Jun 2025 12:00:00 +0000</pubDate>
      <link>https://forem.com/steeve/composant-stepper-avec-riotjs-2e5d</link>
      <guid>https://forem.com/steeve/composant-stepper-avec-riotjs-2e5d</guid>
      <description>&lt;p&gt;Cet article traite de la création d'un composant Stepper (étapes) avec RiotJS, en utilisant le CSS Material Design BeerCSS. Avant de commencer, assurez-vous d'avoir une application Riot, ou lisez mes articles précédents.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Je suppose que vous avez une compréhension fondamentale de Riot ; cependant, n'hésitez pas à vous référer à la documentation si nécessaire : &lt;a href="https://riot.js.org/documentation/" rel="noopener noreferrer"&gt;https://riot.js.org/documentation/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Les steppers, ou "étapes" en Français, affichent la progression à travers un processus multi-étapes. Les utilisateurs savent intuitivement où ils en sont dans le processus et combien d'étapes restent, par exemple, un flux de paiement, une connexion ou un formulaire.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F88kakb2uj4y1j1lymaz9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F88kakb2uj4y1j1lymaz9.png" alt="Image description" width="800" height="623"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Base du composant Stepper
&lt;/h2&gt;

&lt;p&gt;L'objectif est de créer une application Riot avec un Stepper qui montre une progression lorsqu'un bouton est cliqué et affiche la page correspondante.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwy5bskjv4033k30wbh3v.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwy5bskjv4033k30wbh3v.gif" alt="GIF of a Stepper made with RiotJS and BeerCSS" width="1000" height="286"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ouvrez le fichier &lt;strong&gt;index.riot&lt;/strong&gt; à la racine de votre projet Vite, puis ajoutez le code suivant. Le HTML provient de la documentation &lt;a href="https://www.beercss.com/#steppers" rel="noopener noreferrer"&gt;BeerCSS&lt;/a&gt; et j'ai ajouté la syntaxe &lt;a href="https://riot.js.org/documentation/#syntax" rel="noopener noreferrer"&gt;RiotJS&lt;/a&gt; pour la logique :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;index-riot&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"width:800px;padding:20px;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;nav&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"scroll"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"circle small"&lt;/span&gt;  &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;() =&lt;/span&gt;&lt;span class="err"&gt;&amp;gt; &lt;/span&gt;&lt;span class="s"&gt;changeStep(1)}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;if=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;state.active =&lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt; &lt;span class="err"&gt;1&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;1&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;i&lt;/span&gt; &lt;span class="na"&gt;if=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;state.active&lt;/span&gt; &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; 1}&amp;gt;done&lt;span class="nt"&gt;&amp;lt;/i&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"max divider"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"circle small"&lt;/span&gt; &lt;span class="na"&gt;disabled=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;state.active&lt;/span&gt; &lt;span class="err"&gt;&amp;lt;&lt;/span&gt; &lt;span class="err"&gt;2&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;() =&lt;/span&gt;&lt;span class="err"&gt;&amp;gt; &lt;/span&gt;&lt;span class="s"&gt;changeStep(2)}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;if=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;state.active&lt;/span&gt; &lt;span class="err"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="err"&gt;2&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;2&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;i&lt;/span&gt; &lt;span class="na"&gt;if=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;state.active&lt;/span&gt; &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; 2}&amp;gt;done&lt;span class="nt"&gt;&amp;lt;/i&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"max divider"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"circle small"&lt;/span&gt; &lt;span class="na"&gt;disabled=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;state.active&lt;/span&gt; &lt;span class="err"&gt;&amp;lt;&lt;/span&gt; &lt;span class="err"&gt;3&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;() =&lt;/span&gt;&lt;span class="err"&gt;&amp;gt; &lt;/span&gt;&lt;span class="s"&gt;changeStep(3)}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;if=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;state.active&lt;/span&gt; &lt;span class="err"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="err"&gt;3&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;3&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;i&lt;/span&gt; &lt;span class="na"&gt;if=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;state.active&lt;/span&gt; &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; 3}&amp;gt;done&lt;span class="nt"&gt;&amp;lt;/i&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/nav&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;br&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"page padding { state.active === 1 ? 'active' : null}"&lt;/span&gt; &lt;span class="na"&gt;if=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;state.active =&lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt; &lt;span class="err"&gt;1&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;h5&amp;gt;&lt;/span&gt;Page { state.active }&lt;span class="nt"&gt;&amp;lt;/h5&amp;gt;&amp;lt;br&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;() =&lt;/span&gt;&lt;span class="err"&gt;&amp;gt; &lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;changeStep&lt;/span&gt;&lt;span class="err"&gt;(2)&lt;/span&gt; &lt;span class="err"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Next&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"page padding { state.active === 2 ? 'active' : null}"&lt;/span&gt; &lt;span class="na"&gt;if=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;state.active =&lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt; &lt;span class="err"&gt;2&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;h5&amp;gt;&lt;/span&gt;Page { state.active }&lt;span class="nt"&gt;&amp;lt;/h5&amp;gt;&amp;lt;br&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;() =&lt;/span&gt;&lt;span class="err"&gt;&amp;gt; &lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;changeStep&lt;/span&gt;&lt;span class="err"&gt;(3)&lt;/span&gt; &lt;span class="err"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Next&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"page padding { state.active === 3 ? 'active' : null}"&lt;/span&gt; &lt;span class="na"&gt;if=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;state.active =&lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt; &lt;span class="err"&gt;3&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;h5&amp;gt;&lt;/span&gt;Page { state.active }&lt;span class="nt"&gt;&amp;lt;/h5&amp;gt;&amp;lt;br&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;() =&lt;/span&gt;&lt;span class="err"&gt;&amp;gt; &lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;changeStep&lt;/span&gt;&lt;span class="err"&gt;(4)&lt;/span&gt; &lt;span class="err"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Next&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"page padding { state.active === 4 ? 'active' : null}"&lt;/span&gt; &lt;span class="na"&gt;if=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;state.active =&lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt; &lt;span class="err"&gt;4&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;h5&amp;gt;&lt;/span&gt;Done!&lt;span class="nt"&gt;&amp;lt;/h5&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
        &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="nf"&gt;changeStep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                    &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;
                &lt;span class="p"&gt;})&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/index-riot&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Code Source: &lt;a href="https://github.com/steevepay/riot-beercss/blob/main/examples/index.stepper.riot" rel="noopener noreferrer"&gt;https://github.com/steevepay/riot-beercss/blob/main/examples/index.stepper.riot&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Décomposons le code :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Le Stepper est composé de boutons et de séparateurs, l'état d'une étape est défini par :

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Complété&lt;/strong&gt; : lorsque l'icône de validation est affichée et que le numéro est masqué avec &lt;code&gt;&amp;lt;template if={ state.active === 1 }&amp;gt;1&amp;lt;/template&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;En cours de complétion&lt;/strong&gt; : lorsque le numéro est affiché et que l'icône de validation est masquée avec &lt;code&gt;&amp;lt;i if={ state.active &amp;gt; 1}&amp;gt;done&amp;lt;/i&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Étape suivante à venir&lt;/strong&gt; : lorsque le bouton est désactivé avec la condition &lt;code&gt;disabled={ state.active &amp;lt; 2 }&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;L'état du Stepper est stocké dans un objet Riot &lt;code&gt;state:{}&lt;/code&gt; sous la valeur &lt;code&gt;state.active&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;state.active&lt;/code&gt; affichera les pages 1, 2 ou 3 avec l'expression &lt;code&gt;&amp;lt;div class="page padding" if={ state.active === 1 }&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Si l'un des boutons d'étape est cliqué, il mettra à jour directement &lt;code&gt;state.active&lt;/code&gt; avec le numéro de l'étape sélectionnée : La fonction &lt;code&gt;changeStep&lt;/code&gt; est déclenchée lorsque l'événement "Click" est capturé, comme : &lt;code&gt;onclick={ () =&amp;gt; changeStep(1)}&lt;/code&gt;. Changer l'étape peut être utilisé pour requêter une API et/ou charger ensuite une page spécifique.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Test du composant Stepper
&lt;/h2&gt;

&lt;p&gt;Il existe deux méthodes pour tester le composant Stepper, couvertes dans deux articles différents :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/steeve/test-unitaire-de-composant-riot-avec-vitest-environnement-node-24j7"&gt;Test avec Vitest et Riot-SSR dans un environnement Node&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/steeve/test-unitaire-de-composant-riot-avec-vitest-jsdom-env-16a"&gt;Test avec Vitest dans un environnement JsDom&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Voilà 🎉 Nous avons créé un composant Stepper Riot en utilisant des éléments Material Design avec BeerCSS. N'hésitez pas à commenter si vous avez des questions ou besoin d'aide avec RiotJS.&lt;/p&gt;

&lt;p&gt;Passez une excellente journée ! Santé 🍻&lt;/p&gt;

</description>
      <category>riotjs</category>
      <category>french</category>
      <category>frontend</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Composant Menu avec RiotJS</title>
      <dc:creator>Steeve</dc:creator>
      <pubDate>Mon, 26 May 2025 12:00:00 +0000</pubDate>
      <link>https://forem.com/steeve/composant-menu-avec-riotjs-400f</link>
      <guid>https://forem.com/steeve/composant-menu-avec-riotjs-400f</guid>
      <description>&lt;p&gt;Cet article traite de la création d'un composant de menu avec RiotJS, en utilisant le CSS Material Design BeerCSS. Avant de commencer, assurez-vous d'avoir une application Riot, ou lisez mes articles précédents de la série.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Je suppose que vous avez une compréhension fondamentale de Riot ; cependant, n'hésitez pas à vous référer à la documentation si nécessaire : &lt;a href="https://riot.js.org/documentation/" rel="noopener noreferrer"&gt;https://riot.js.org/documentation/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Un menu s'ouvre lors de l'interaction avec un élément (comme une icône, un bouton ou un champ de saisie) ou lorsque les utilisateurs effectuent une action spécifique. Le menu affiche une liste de choix sur une surface temporaire, permettant aux utilisateurs de faire une sélection pour exécuter des actions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuq5ec1bsubfr51lsjcd8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuq5ec1bsubfr51lsjcd8.png" alt="Example of a Menu opening when a button is clicked" width="800" height="467"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Base du composant de menu
&lt;/h2&gt;

&lt;p&gt;L'objectif est de créer une application Riot avec un menu apparaissant lorsqu'un bouton est cliqué, de le masquer lorsqu'un élément est cliqué, et d'exécuter une action. &lt;u&gt;Bonus :&lt;/u&gt; Masquer le menu lorsqu'un clic se produit en dehors du composant.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff7ly06oolsymdnscosir.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff7ly06oolsymdnscosir.gif" alt="GIF of a Menu Component made with RiotJS and BeerCSS" width="800" height="574"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pour afficher un menu lorsqu'un bouton est cliqué :&lt;/strong&gt; Le menu fait partie du composant &lt;code&gt;Button&lt;/code&gt;, en tant que &lt;a href="https://riot.js.org/documentation/#slots" rel="noopener noreferrer"&gt;Slot&lt;/a&gt;. La balise &lt;code&gt;&amp;lt;slot&amp;gt;&lt;/code&gt; de Riot injecte des modèles HTML personnalisés dans un composant enfant à partir de son parent.&lt;/p&gt;

&lt;p&gt;Le code suivant du composant Bouton est utilisé pour rendre le menu visible, situé dans &lt;strong&gt;./components/c-button.riot&lt;/strong&gt;. Le HTML provient de la documentation &lt;a href="https://www.beercss.com/#buttons" rel="noopener noreferrer"&gt;BeerCSS&lt;/a&gt; et j'ai ajouté la syntaxe &lt;a href="https://riot.js.org/documentation/#syntax" rel="noopener noreferrer"&gt;RiotJS&lt;/a&gt; pour la logique :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;c-button&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&amp;lt;slot&amp;gt;&amp;lt;/slot&amp;gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;i&lt;/span&gt; &lt;span class="na"&gt;icon=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="err"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;icon&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;props?.icon&lt;span class="nt"&gt;&amp;lt;/i&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;slot&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"menu"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/slot&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/c-button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Cliquez ici pour en apprendre plus sur créer un &lt;a href="https://dev.to/steeve/composant-bouton-avec-riotjs-egj"&gt;composant Button&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Décomposons le code :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Les balises &lt;code&gt;&amp;lt;c-button&amp;gt;&lt;/code&gt; et &lt;code&gt;&amp;lt;/c-button&amp;gt;&lt;/code&gt; définissent une balise racine personnalisée, portant le même nom que le fichier. Vous devez l'écrire ; sinon, cela pourrait créer des résultats inattendus. Utiliser la balise &lt;code&gt;&amp;lt;button&amp;gt;&amp;lt;/button&amp;gt;&lt;/code&gt; comme balise racine ou redéfinir des balises HTML natives est une mauvaise pratique ; commencer par &lt;code&gt;c-&lt;/code&gt; est une bonne convention.&lt;/li&gt;
&lt;li&gt;L'étiquette du bouton est passée en tant que &lt;a href="https://riot.js.org/documentation/#slots" rel="noopener noreferrer"&gt;Slot&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Le menu est passé en tant que Slot nommé "Menu" : &lt;code&gt;&amp;lt;slot name="menu"&amp;gt;&amp;lt;/slot&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Une icône optionnelle peut être passée en tant qu'attribut si &lt;code&gt;props.icon&lt;/code&gt; existe ; elle affichera une icône &lt;a href="https://fonts.google.com/icons" rel="noopener noreferrer"&gt;Google Font&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Enfin, chargez et instanciez &lt;strong&gt;c-button.riot&lt;/strong&gt; dans une page principale nommée &lt;strong&gt;index.riot&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;index-riot&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"width:600px;padding:20px;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;c-button&lt;/span&gt; &lt;span class="na"&gt;icon=&lt;/span&gt;&lt;span class="s"&gt;"arrow_drop_down"&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;(ev) =&lt;/span&gt;&lt;span class="err"&gt;&amp;gt; &lt;/span&gt;&lt;span class="s"&gt;toggle(ev,&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="na"&gt;button&lt;/span&gt;&lt;span class="err"&gt;')&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onfocusout=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;() =&lt;/span&gt;&lt;span class="err"&gt;&amp;gt; &lt;/span&gt;&lt;span class="s"&gt;update({&lt;/span&gt; &lt;span class="na"&gt;active:&lt;/span&gt; &lt;span class="na"&gt;false&lt;/span&gt; &lt;span class="err"&gt;})}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            Menu
            &lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;slot=&lt;/span&gt;&lt;span class="s"&gt;"menu"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;menu&lt;/span&gt;  &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"no-wrap{ state.active === true ? ' active' : ''}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"row"&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;(ev) =&lt;/span&gt;&lt;span class="err"&gt;&amp;gt; &lt;/span&gt;&lt;span class="s"&gt;toggle(ev,&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="na"&gt;item1&lt;/span&gt;&lt;span class="err"&gt;')&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;i&amp;gt;&lt;/span&gt;visibility&lt;span class="nt"&gt;&amp;lt;/i&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"max"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Item 1&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"row"&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;(ev) =&lt;/span&gt;&lt;span class="err"&gt;&amp;gt; &lt;/span&gt;&lt;span class="s"&gt;toggle(ev,&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="na"&gt;item2&lt;/span&gt;&lt;span class="err"&gt;')&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;i&amp;gt;&lt;/span&gt;content_copy&lt;span class="nt"&gt;&amp;lt;/i&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"max"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Item 2&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;⌘C&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"row"&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;(ev) =&lt;/span&gt;&lt;span class="err"&gt;&amp;gt; &lt;/span&gt;&lt;span class="s"&gt;toggle(ev,&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="na"&gt;item3&lt;/span&gt;&lt;span class="err"&gt;')&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;i&amp;gt;&lt;/span&gt;edit&lt;span class="nt"&gt;&amp;lt;/i&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"max"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Item 3&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"small-divider"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"row"&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;(ev) =&lt;/span&gt;&lt;span class="err"&gt;&amp;gt; &lt;/span&gt;&lt;span class="s"&gt;toggle(ev,&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="na"&gt;item4&lt;/span&gt;&lt;span class="err"&gt;')&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"circle tiny"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"../favicon.png"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"max"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                            &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;Item 4&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
                            &lt;span class="nt"&gt;&amp;lt;label&amp;gt;&lt;/span&gt;Some text here&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/menu&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/c-button&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
        &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;cButton&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../components/c-button.riot&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

        &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;components&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;cButton&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="nf"&gt;toggle &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stopPropagation&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
                &lt;span class="nx"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
                &lt;span class="c1"&gt;// Hide the menu&lt;/span&gt;
                &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;active&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
                &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;origin&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;item1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="c1"&gt;// do something&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;origin&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;item2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="c1"&gt;// do something else&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/index-riot&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Code Source: &lt;a href="https://github.com/steevepay/riot-beercss/blob/main/examples/index.menu.riot" rel="noopener noreferrer"&gt;https://github.com/steevepay/riot-beercss/blob/main/examples/index.menu.riot&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Détails du code :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Le composant est importé avec &lt;code&gt;import cButton from "./components/c-button.riot";&lt;/code&gt; puis chargé dans l'objet Riot &lt;code&gt;components:{}&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Le composant button est instancié avec &lt;code&gt;&amp;lt;c-button&amp;gt;&lt;/code&gt; dans le HTML.&lt;/li&gt;
&lt;li&gt;Le menu est passé en tant que slot dans une balise HTML &lt;code&gt;&amp;lt;menu&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Chaque élément de la liste a l'architecture suivante, enveloppée dans une balise &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; avec une icône et une étiquette : &lt;code&gt;&amp;lt;a class="row"&amp;gt;&amp;lt;i&amp;gt;icon&amp;lt;/i&amp;gt;&amp;lt;span class="max"&amp;gt;Label&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;L'état du menu est stocké dans un objet Riot &lt;code&gt;state:{}&lt;/code&gt;, via la variable booléenne &lt;code&gt;state.active&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Pour rendre le menu visible, le menu doit contenir la classe "active" : Lorsque &lt;code&gt;state.active&lt;/code&gt; est vrai (true), il applique la classe "active" ; sinon, il n'applique rien.&lt;/li&gt;
&lt;li&gt;Lorsqu'un clic se produit sur le bouton, la fonction &lt;code&gt;toggle&lt;/code&gt; est exécutée pour attribuer le booléen opposé à &lt;code&gt;state.active&lt;/code&gt;. En même temps, une chaîne est passée à la fonction &lt;code&gt;toggle&lt;/code&gt; pour définir l'origine du clic, soit : &lt;code&gt;button&lt;/code&gt;, soit un élément du menu. Grâce à l'origine, une fonction spécifique peut être exécutée : appels API, ouverture d'une page, et toute autre action !&lt;/li&gt;
&lt;li&gt;Lorsqu'un clic se produit en dehors du menu, l'événement "focusout" est capturé pour masquer le menu avec l'expression : &lt;code&gt;onfocusout={ () =&amp;gt; update({ active: false })}&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Un élément du menu peut avoir un style différent, par exemple, le dernier élément de la liste affiche une image au lieu d'une icône, suivie d'un titre et d'un sous-titre. Trouvez tous les exemples de menu sur la documentation des menus BeerCSS.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Test du composant de menu
&lt;/h2&gt;

&lt;p&gt;Il existe deux méthodes pour tester le composant de menu, couvertes dans deux articles différents :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/steeve/test-unitaire-de-composant-riot-avec-vitest-environnement-node-24j7"&gt;Test avec Vitest et Riot-SSR dans un environnement Node&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/steeve/test-unitaire-de-composant-riot-avec-vitest-jsdom-env-16a"&gt;Test avec Vitest dans un environnement JsDom&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Voilà 🎉 Nous avons créé un composant de menu Riot en utilisant des éléments Material Design avec BeerCSS. Le code source de la barre de menu est disponible sur Github : &lt;a href="https://github.com/steevepay/riot-beercss/blob/main/components/c-menu.riot" rel="noopener noreferrer"&gt;https://github.com/steevepay/riot-beercss/blob/main/components/c-menu.riot&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Passez une excellente journée ! Santé 🍻&lt;/p&gt;

</description>
      <category>riotjs</category>
      <category>french</category>
      <category>frontend</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Composant Snackbar avec RiotJS</title>
      <dc:creator>Steeve</dc:creator>
      <pubDate>Mon, 19 May 2025 12:00:00 +0000</pubDate>
      <link>https://forem.com/steeve/composant-snackbar-avec-riotjs-540h</link>
      <guid>https://forem.com/steeve/composant-snackbar-avec-riotjs-540h</guid>
      <description>&lt;p&gt;Cet article traite de la création d'un composant Snackbar avec Riot, en utilisant le CSS Material Design BeerCSS, et de l'exécution d'une action lors des événements d'entrée et de sélection.&lt;/p&gt;

&lt;p&gt;Avant de commencer, assurez-vous d'avoir une application de base Riot, ou consultez mes articles précédents.&lt;/p&gt;

&lt;p&gt;Les Snackbars communiquent des messages en bas de l'écran, qui sont minimalement interruptifs et ne nécessitent pas d'action de l'utilisateur. Ils peuvent contenir une seule action, telle que "Annuler", "Ouvrir", ou "En savoir plus".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnrli31lo13nbf486jegt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnrli31lo13nbf486jegt.png" alt="Example of snackbar showing on a mobile app" width="800" height="355"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Base du Composant Snackbar
&lt;/h2&gt;

&lt;p&gt;L'objectif est de créer une application Riot avec une Snackbar apparaissant lorsqu'un bouton est cliqué, et de la faire disparaître automatiquement lorsque l'action est cliquée.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnntmy8q4ur4mp8t5e8j2.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnntmy8q4ur4mp8t5e8j2.gif" alt="Gif of a Snackbar made with RiotJS displayed when a button is click" width="800" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Tout d'abord, créez un nouveau fichier nommé &lt;strong&gt;c-snackbar.riot&lt;/strong&gt; dans le dossier des composants. Le préfixe &lt;code&gt;c-&lt;/code&gt; signifie "composant", une convention de nommage utile et une bonne pratique.&lt;/p&gt;

&lt;p&gt;Écrivez le code suivant dans &lt;code&gt;./components/c-snackbar.riot&lt;/code&gt;. Le HTML provient de la documentation &lt;a href="https://www.beercss.com/#snackbars" rel="noopener noreferrer"&gt;BeerCSS&lt;/a&gt; et j'ai ajouté la syntaxe &lt;a href="https://riot.js.org/documentation/#syntax" rel="noopener noreferrer"&gt;RiotJS&lt;/a&gt; pour la logique :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;c-snackbar&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"
            snackbar
            { props?.active ? 'active ' : null }
            { props?.top ? 'top ' : null }
            { props?.bottom ? 'bottom ' : null }
            { props?.error ? 'error ' : null }
            { props?.primary ? 'primary ' : null }
            { props?.secondary ? 'secondary ' : null }
            { props?.tertiary ? 'tertiary ' : null }
        "&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;i&lt;/span&gt; &lt;span class="na"&gt;if=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="err"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;icon&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{props.icon}&lt;span class="nt"&gt;&amp;lt;/i&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"max"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;slot&amp;gt;&amp;lt;/slot&amp;gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;if=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="err"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;action&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;clicked&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"inverse-link"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{ props?.action }&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
        &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;clicked &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
                &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stopPropagation&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
                &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dispatchEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;action&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/c-snackbar&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Source Code: &lt;a href="https://github.com/steevepay/riot-beercss/blob/main/components/c-snackbar.riot" rel="noopener noreferrer"&gt;https://github.com/steevepay/riot-beercss/blob/main/components/c-snackbar.riot&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Expliquons le code :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Les balises &lt;code&gt;&amp;lt;c-snackbar&amp;gt;&lt;/code&gt; et &lt;code&gt;&amp;lt;/c-snackbar&amp;gt;&lt;/code&gt; définissent une balise racine personnalisée, portant le même nom que le fichier. Vous devez l'écrire ; sinon, cela pourrait créer des résultats inattendus. Utiliser la balise &lt;code&gt;&amp;lt;div&amp;gt;&amp;lt;/div&amp;gt;&lt;/code&gt; comme balise racine ou redéfinir des balises HTML natives est une mauvaise pratique, donc commencer par &lt;code&gt;c-&lt;/code&gt; est une bonne convention.&lt;/li&gt;
&lt;li&gt;Le message est passé en tant que balise &lt;a href="https://riot.js.org/api/#slots" rel="noopener noreferrer"&gt;Slot&lt;/a&gt; &lt;code&gt;&amp;lt;slot&amp;gt;&amp;lt;/slot&amp;gt;&lt;/code&gt;, une fonctionnalité centrale de Riot.js permettant d'injecter des modèles HTML personnalisés dans un composant enfant depuis son parent. Dans notre cas, seule une chaîne est injectée, sans HTML.&lt;/li&gt;
&lt;li&gt;Les Snackbars peuvent afficher un &lt;u&gt;bouton permettant aux utilisateurs d'agir (Call to action)&lt;/u&gt; sur un processus effectué par l'application : Si l'attribut &lt;code&gt;props.action&lt;/code&gt; existe, le message est affiché à l'intérieur du bouton d'action.&lt;/li&gt;
&lt;li&gt;
&lt;u&gt;Lorsque le bouton d'action est cliqué :&lt;/u&gt; L'événement &lt;code&gt;click&lt;/code&gt; est capturé et exécute la fonction &lt;code&gt;clicked&lt;/code&gt; pour émettre un événement personnalisé nommé action.&lt;/li&gt;
&lt;li&gt;Pour afficher la Snackbar, elle doit contenir la classe active : lorsque l'attribut props.active existe, il ajoute la classe active grâce à l'expression : &lt;code&gt;{ props?.active ? 'active ' : null }&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Différents styles sont disponibles pour le composant, par exemple, primary est appliqué si &lt;code&gt;props?.primary&lt;/code&gt; existe et est vrai.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Enfin, chargez et instanciez le composant &lt;strong&gt;c-snackbar.riot&lt;/strong&gt; dans une page principale nommée &lt;strong&gt;index.riot&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;index-riot&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"width:600px;padding:20px;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;c-button&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;() =&lt;/span&gt;&lt;span class="err"&gt;&amp;gt; &lt;/span&gt;&lt;span class="s"&gt;openSnack("default")&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;inverse=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;true&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Default&lt;span class="nt"&gt;&amp;lt;/c-button&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;c-button&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;() =&lt;/span&gt;&lt;span class="err"&gt;&amp;gt; &lt;/span&gt;&lt;span class="s"&gt;openSnack("error")&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;error=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;true&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Error&lt;span class="nt"&gt;&amp;lt;/c-button&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;c-button&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;() =&lt;/span&gt;&lt;span class="err"&gt;&amp;gt; &lt;/span&gt;&lt;span class="s"&gt;openSnack("primary")&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;primary=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;true&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Primary&lt;span class="nt"&gt;&amp;lt;/c-button&amp;gt;&lt;/span&gt;

        &lt;span class="nt"&gt;&amp;lt;c-snackbar&lt;/span&gt; 
            &lt;span class="na"&gt;active=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;state.active&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;onaction=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;close&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;error=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;state.error&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; 
            &lt;span class="na"&gt;icon=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;state.icon&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; 
            &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;state.action&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;primary=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;state.primary&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            { state.message }
        &lt;span class="nt"&gt;&amp;lt;/c-snackbar&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
        &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;cButton&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../components/c-button.riot&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;cSnackbar&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../components/c-snackbar.riot&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

        &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;components&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;cSnackbar&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nx"&gt;cButton&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="nf"&gt;openSnack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;active&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; 
                    &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Something went wrong.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Email Archived.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Contact Support&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Undo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;check&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;primary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;primary&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
                &lt;span class="p"&gt;})&lt;/span&gt;
                &lt;span class="nf"&gt;clearTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timeout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="nf"&gt;close &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/index-riot&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Source Code: &lt;a href="https://github.com/steevepay/riot-beercss/blob/main/examples/index.snackbar.riot" rel="noopener noreferrer"&gt;https://github.com/steevepay/riot-beercss/blob/main/examples/index.snackbar.riot&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Détails du code :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Le composant est importé avec &lt;code&gt;import cSnackbar from "./components/c-snackbar.riot";&lt;/code&gt; puis chargé dans l'objet Riot &lt;code&gt;components:{}&lt;/code&gt;. Un composant &lt;code&gt;Button&lt;/code&gt; est également chargé dans la page : lorsqu'un clic se produit, il affiche le &lt;code&gt;toaster&lt;/code&gt; avec un message personnalisé !&lt;/li&gt;
&lt;li&gt;Le composant snackbar est instancié avec &lt;code&gt;&amp;lt;c-snackbar /&amp;gt;&lt;/code&gt; dans le HTML.&lt;/li&gt;
&lt;li&gt;L'état du composant, tel que &lt;code&gt;active&lt;/code&gt;, est stocké dans l'objet Riot &lt;code&gt;state:{}&lt;/code&gt; sous la propriété booléenne state.active. La propriété est passée en tant qu'attribut, comme : &lt;code&gt;&amp;lt;c-snackbar active={ state.active } /&amp;gt;&lt;/code&gt;. Pour rendre le toaster complètement interactif, d'autres états sont stockés : le message, l'icône et le libellé de l'action.&lt;/li&gt;
&lt;li&gt;Lorsqu'un bouton est cliqué, la fonction openSnack est exécutée grâce à onclick={ () =&amp;gt; openSnack("default") }. Un type est passé en premier argument pour sélectionner le type de Snackbar, le message, l'icône et l'action. À la fin, le toaster est affiché en mettant à jour state.active sur vrai.&lt;/li&gt;
&lt;li&gt;Pour faire disparaître automatiquement le toaster, un timeout est créé pour masquer le Snackbar en mettant à jour &lt;code&gt;state.active&lt;/code&gt; sur &lt;code&gt;false&lt;/code&gt; après 2 secondes.&lt;/li&gt;
&lt;li&gt;L'événement personnalisé action est surveillé avec &lt;code&gt;onaction&lt;/code&gt; : si un clic déclenche l'action du Snackbar, la fonction &lt;code&gt;close&lt;/code&gt; met à jour &lt;code&gt;state.active&lt;/code&gt; pour la faire disparaître.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Tests du Composant Snackbar
&lt;/h2&gt;

&lt;p&gt;Il existe deux méthodes pour tester le composant Snackbar, et elles sont couvertes dans deux articles différents :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/steeve/test-unitaire-de-composant-riot-avec-vitest-environnement-node-24j7"&gt;Test avec Vitest et Riot-SSR dans un environnement Node&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/steeve/test-unitaire-de-composant-riot-avec-vitest-jsdom-env-16a"&gt;Test avec Vitest dans un environnement JsDom&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Conclusion&lt;/p&gt;

&lt;p&gt;Voilà 🎉 Nous avons créé un composant Snackbar Riot en utilisant des éléments Material Design avec BeerCSS. Le code source est disponible sur Github : &lt;a href="https://github.com/steevepay/riot-beercss/blob/main/components/c-snackbar.riot" rel="noopener noreferrer"&gt;https://github.com/steevepay/riot-beercss/blob/main/components/c-snackbar.riot&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bonne journée ! Santé 🍻&lt;/p&gt;

</description>
      <category>riotjs</category>
      <category>french</category>
      <category>frontend</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Composant Recherche avec RiotJS</title>
      <dc:creator>Steeve</dc:creator>
      <pubDate>Mon, 12 May 2025 12:00:00 +0000</pubDate>
      <link>https://forem.com/steeve/composant-recherche-avec-riotjs-57a9</link>
      <guid>https://forem.com/steeve/composant-recherche-avec-riotjs-57a9</guid>
      <description>&lt;p&gt;Cet article traite de la création d'un composant de recherche (Search) avec Riot, en utilisant le CSS Material Design BeerCSS, et de l'exécution d'une action lors des événements d'entrée et de sélection.&lt;/p&gt;

&lt;p&gt;Avant de commencer, assurez-vous d'avoir une application de base RiotJS, ou consultez mes articles précédents.&lt;/p&gt;

&lt;p&gt;La recherche permet aux utilisateurs d'entrer un mot-clé ou une phrase pour obtenir des informations pertinentes : Les utilisateurs saisissent une requête dans la barre de recherche (1) et voient ensuite les résultats associés (2).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2vf9bvqljl62bi42hdo5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2vf9bvqljl62bi42hdo5.png" alt="Image description" width="800" height="266"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Base du Composant de Recherche
&lt;/h2&gt;

&lt;p&gt;L'objectif est de créer une application Riot avec une barre de recherche, d'afficher les résultats de recherche, et d'exécuter une action lorsqu'un résultat est sélectionné.&lt;/p&gt;

&lt;p&gt;Tout d'abord, créez un nouveau fichier nommé &lt;strong&gt;c-search.riot&lt;/strong&gt; dans le dossier des composants. Le préfixe &lt;code&gt;c-&lt;/code&gt; signifie "composant", une convention de nommage utile et une bonne pratique.&lt;/p&gt;

&lt;p&gt;Écrivez le code suivant dans &lt;strong&gt;./components/c-search.riot&lt;/strong&gt;. Le HTML provient de la documentation &lt;a href="https://www.beercss.com/#search" rel="noopener noreferrer"&gt;BeerCSS&lt;/a&gt; et j'ai ajouté la syntaxe &lt;a href="https://riot.js.org/documentation/#syntax" rel="noopener noreferrer"&gt;RiotJS&lt;/a&gt; pour la logique :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;c-search&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"field prefix
        { props?.outlined ? "&lt;/span&gt; &lt;span class="na"&gt;border&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt; &lt;span class="na"&gt;:&lt;/span&gt; &lt;span class="err"&gt;''}&lt;/span&gt;
        &lt;span class="err"&gt;{&lt;/span&gt; &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="err"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;round&lt;/span&gt; &lt;span class="err"&gt;?&lt;/span&gt; &lt;span class="err"&gt;"&lt;/span&gt; &lt;span class="na"&gt;round&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt; &lt;span class="na"&gt;:&lt;/span&gt; &lt;span class="err"&gt;''}&lt;/span&gt;
        &lt;span class="err"&gt;{&lt;/span&gt; &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="err"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;fill&lt;/span&gt; &lt;span class="err"&gt;?&lt;/span&gt; &lt;span class="err"&gt;"&lt;/span&gt; &lt;span class="na"&gt;fill&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt; &lt;span class="na"&gt;:&lt;/span&gt; &lt;span class="err"&gt;''}&lt;/span&gt;
        &lt;span class="err"&gt;{&lt;/span&gt; &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="err"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;small&lt;/span&gt; &lt;span class="err"&gt;?&lt;/span&gt; &lt;span class="err"&gt;"&lt;/span&gt; &lt;span class="na"&gt;small&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt; &lt;span class="na"&gt;:&lt;/span&gt; &lt;span class="err"&gt;''}&lt;/span&gt;
        &lt;span class="err"&gt;{&lt;/span&gt; &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="err"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;medium&lt;/span&gt; &lt;span class="err"&gt;?&lt;/span&gt; &lt;span class="err"&gt;"&lt;/span&gt; &lt;span class="na"&gt;medium&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt; &lt;span class="na"&gt;:&lt;/span&gt; &lt;span class="err"&gt;''}&lt;/span&gt;
        &lt;span class="err"&gt;{&lt;/span&gt; &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="err"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;large&lt;/span&gt; &lt;span class="err"&gt;?&lt;/span&gt; &lt;span class="err"&gt;"&lt;/span&gt; &lt;span class="na"&gt;large&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt; &lt;span class="na"&gt;:&lt;/span&gt; &lt;span class="err"&gt;''}&lt;/span&gt;
        &lt;span class="err"&gt;{&lt;/span&gt; &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="err"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;extra&lt;/span&gt; &lt;span class="err"&gt;?&lt;/span&gt; &lt;span class="err"&gt;"&lt;/span&gt; &lt;span class="na"&gt;extra&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt; &lt;span class="na"&gt;:&lt;/span&gt; &lt;span class="err"&gt;''}&lt;/span&gt;
        &lt;span class="err"&gt;{&lt;/span&gt; &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="err"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt; &lt;span class="err"&gt;?&lt;/span&gt; &lt;span class="err"&gt;"&lt;/span&gt; &lt;span class="na"&gt;invalid&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt; &lt;span class="na"&gt;:&lt;/span&gt; &lt;span class="err"&gt;''&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;
        &lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;progress&lt;/span&gt; &lt;span class="na"&gt;if=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="err"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;loading&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"circle"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/progress&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;i&lt;/span&gt; &lt;span class="na"&gt;if=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="err"&gt;!&lt;/span&gt;&lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="err"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;loading&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"front"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{ props?.iconSearch ?  props.iconSearch : "search"}&lt;span class="nt"&gt;&amp;lt;/i&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="err"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="err"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;placeholder&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;menu&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"{ props?.max ? "&lt;/span&gt;&lt;span class="na"&gt;max&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt; &lt;span class="na"&gt;:&lt;/span&gt; &lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="na"&gt;min&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt; &lt;span class="err"&gt;}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"field prefix suffix no-margin fixed         
                            { props?.outlined ? "&lt;/span&gt; &lt;span class="na"&gt;border&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt; &lt;span class="na"&gt;:&lt;/span&gt; &lt;span class="err"&gt;''}&lt;/span&gt;
                            &lt;span class="err"&gt;{&lt;/span&gt; &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="err"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;round&lt;/span&gt; &lt;span class="err"&gt;?&lt;/span&gt; &lt;span class="err"&gt;"&lt;/span&gt; &lt;span class="na"&gt;round&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt; &lt;span class="na"&gt;:&lt;/span&gt; &lt;span class="err"&gt;''}&lt;/span&gt;
                            &lt;span class="err"&gt;{&lt;/span&gt; &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="err"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;fill&lt;/span&gt; &lt;span class="err"&gt;?&lt;/span&gt; &lt;span class="err"&gt;"&lt;/span&gt; &lt;span class="na"&gt;fill&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt; &lt;span class="na"&gt;:&lt;/span&gt; &lt;span class="err"&gt;''}&lt;/span&gt;
                            &lt;span class="err"&gt;{&lt;/span&gt; &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="err"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;small&lt;/span&gt; &lt;span class="err"&gt;?&lt;/span&gt; &lt;span class="err"&gt;"&lt;/span&gt; &lt;span class="na"&gt;small&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt; &lt;span class="na"&gt;:&lt;/span&gt; &lt;span class="err"&gt;''}&lt;/span&gt;
                            &lt;span class="err"&gt;{&lt;/span&gt; &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="err"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;medium&lt;/span&gt; &lt;span class="err"&gt;?&lt;/span&gt; &lt;span class="err"&gt;"&lt;/span&gt; &lt;span class="na"&gt;medium&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt; &lt;span class="na"&gt;:&lt;/span&gt; &lt;span class="err"&gt;''}&lt;/span&gt;
                            &lt;span class="err"&gt;{&lt;/span&gt; &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="err"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;large&lt;/span&gt; &lt;span class="err"&gt;?&lt;/span&gt; &lt;span class="err"&gt;"&lt;/span&gt; &lt;span class="na"&gt;large&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt; &lt;span class="na"&gt;:&lt;/span&gt; &lt;span class="err"&gt;''}&lt;/span&gt;
                            &lt;span class="err"&gt;{&lt;/span&gt; &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="err"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;extra&lt;/span&gt; &lt;span class="err"&gt;?&lt;/span&gt; &lt;span class="err"&gt;"&lt;/span&gt; &lt;span class="na"&gt;extra&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt; &lt;span class="na"&gt;:&lt;/span&gt; &lt;span class="err"&gt;''}&lt;/span&gt;
                            &lt;span class="err"&gt;{&lt;/span&gt; &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="err"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt; &lt;span class="err"&gt;?&lt;/span&gt; &lt;span class="err"&gt;"&lt;/span&gt; &lt;span class="na"&gt;invalid&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt; &lt;span class="na"&gt;:&lt;/span&gt; &lt;span class="err"&gt;''&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;
                        &lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;i&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"front"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{ props?.iconBack ?  props.iconBack : "arrow_back"}&lt;span class="nt"&gt;&amp;lt;/i&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="err"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="err"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;placeholder&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;i&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;clear&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"front"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{ props?.iconClose ?  props.iconClose : "close"}&lt;span class="nt"&gt;&amp;lt;/i&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"row"&lt;/span&gt; &lt;span class="na"&gt;each=&lt;/span&gt;&lt;span class="s"&gt;{res&lt;/span&gt; &lt;span class="na"&gt;in&lt;/span&gt; &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="err"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;results&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;(ev) =&lt;/span&gt;&lt;span class="err"&gt;&amp;gt; &lt;/span&gt;&lt;span class="s"&gt;select(ev,&lt;/span&gt; &lt;span class="na"&gt;res&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;i&amp;gt;&lt;/span&gt;{ res?.icon ?? props?.iconResult ?? 'history' }&lt;span class="nt"&gt;&amp;lt;/i&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;{ res?.label ?? res?.name ?? res }&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/menu&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
        &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
                &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stopPropagation&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
                &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dispatchEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;select&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="nf"&gt;clear &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
                &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stopPropagation&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
                &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dispatchEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;clear&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/c-search&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Source Code: &lt;a href="https://github.com/steevepay/riot-beercss/blob/main/components/c-search.riot" rel="noopener noreferrer"&gt;https://github.com/steevepay/riot-beercss/blob/main/components/c-search.riot&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Expliquons le code :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Les balises &lt;code&gt;&amp;lt;c-search&amp;gt;&lt;/code&gt; et &lt;code&gt;&amp;lt;/c-search&amp;gt;&lt;/code&gt; définissent une balise racine personnalisée, portant le même nom que le fichier. Vous devez l'écrire ; sinon, cela pourrait créer des résultats inattendus. Utiliser la balise &lt;code&gt;&amp;lt;div&amp;gt;&amp;lt;/div&amp;gt;&lt;/code&gt; comme balise racine ou redéfinir des balises HTML natives est une mauvaise pratique, donc commencer par c- est une bonne convention.&lt;/li&gt;
&lt;li&gt;La recherche a deux états :

&lt;ul&gt;
&lt;li&gt;État par défaut : Sans interactions, la barre de recherche principale est un champ de recherche persistant et visible en haut de l'écran : le premier élément HTML &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt; est affiché.&lt;/li&gt;
&lt;li&gt;État de focus : Lors du focus, la barre de recherche s'étend en une vue de recherche, affichant des suggestions de recherche historique : Le second élément HTML &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt; est affiché à l'intérieur d'un élément &lt;code&gt;&amp;lt;menu&amp;gt;&lt;/code&gt; suivi d'une liste de résultats.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;La liste des résultats est affichée grâce à une expression &lt;a href="https://riot.js.org/documentation/#loops" rel="noopener noreferrer"&gt;Each&lt;/a&gt; de Riot : &lt;code&gt;&amp;lt;a class="row" each={res in props?.results}&amp;gt;&amp;lt;/a&amp;gt;&lt;/code&gt;. Le résultat affiche une icône et le nom. Le résultat peut être un tableau d'objets ou un tableau de chaînes ; le nom est alors affiché grâce à la condition : &lt;code&gt;{ res?.label ?? res?.name ?? res }&lt;/code&gt;. Il prend d'abord la propriété &lt;code&gt;label&lt;/code&gt;, puis &lt;code&gt;name&lt;/code&gt; ; sinon, il affiche &lt;code&gt;res&lt;/code&gt; comme une chaîne.&lt;/li&gt;
&lt;li&gt;Si un clic se produit sur l'un des résultats, la fonction &lt;code&gt;select&lt;/code&gt; est exécutée : Un événement personnalisé &lt;code&gt;select&lt;/code&gt; est émis pour notifier les composants supérieurs avec le résultat sélectionné comme valeur.&lt;/li&gt;
&lt;li&gt;Si un clic se produit sur l'icône de fermeture, la fonction &lt;code&gt;reset&lt;/code&gt; est exécutée : Un événement personnalisé &lt;code&gt;clear&lt;/code&gt; est émis pour notifier le composant parent sans valeur.&lt;/li&gt;
&lt;li&gt;L'icône de recherche par défaut peut être remplacée par une icône &lt;a href="https://fonts.google.com/icons" rel="noopener noreferrer"&gt;Google Font&lt;/a&gt; : Fournissez l'attribut icon, accessible sur le composant avec props.icon.&lt;/li&gt;
&lt;li&gt;Le champ de recherche peut avoir différents styles, et ils doivent être fournis en tant qu'attribut HTML, par exemple pour rendre le champ arrondi : &lt;code&gt;{ props?.round ? " round" : ''}&lt;/code&gt; si &lt;code&gt;props.round&lt;/code&gt; existe, la classe round est appliquée aux deux champs.&lt;/li&gt;
&lt;li&gt;Pour afficher les résultats de recherche en plein écran, la propriété &lt;code&gt;props.max&lt;/code&gt; doit exister et être vraie, enfin la classe &lt;code&gt;max&lt;/code&gt; est appliquée sur le &lt;code&gt;&amp;lt;menu&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Enfin, chargez et instanciez le composant &lt;strong&gt;c-search.riot&lt;/strong&gt; dans une page principale nommée *&lt;em&gt;index.riot&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;index-riot&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"width:600px;padding:20px;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;c-search&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Fruit name..."&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;state.value&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onchange=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;changed&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onkeyup=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;changed&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;results=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;state.results&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onselect=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;selected&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onclear=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;reset&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;outlined=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;large=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;round=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;fill=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
        &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;cSearch&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../components/c-search.riot&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;fruits&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./data/fruits.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;_defaultState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;results&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Mango&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Strawberries&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Bananas&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;components&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;cSearch&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;_defaultState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nf"&gt;changed &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; 
                    &lt;span class="na"&gt;value&lt;/span&gt;   &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;results&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;fruits&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
                &lt;span class="p"&gt;})&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="nf"&gt;selected &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="nf"&gt;reset &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_defaultState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/index-riot&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Source Code: &lt;a href="https://github.com/steevepay/riot-beercss/blob/main/examples/index.search.riot" rel="noopener noreferrer"&gt;https://github.com/steevepay/riot-beercss/blob/main/examples/index.search.riot&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Détails du code :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Le composant est importé avec &lt;code&gt;import cSearch from "./components/c-search.riot";&lt;/code&gt; puis chargé dans l'objet Riot &lt;code&gt;components:{}&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Le composant search est instancié avec &lt;code&gt;&amp;lt;c-search /&amp;gt;&lt;/code&gt; dans le HTML.&lt;/li&gt;
&lt;li&gt;L'état de la recherche est stocké dans l'objet Riot &lt;code&gt;state:{}&lt;/code&gt; sous la propriété &lt;code&gt;state.value&lt;/code&gt; de type chaîne. La propriété est passée en tant qu'attribut, comme : &lt;code&gt;&amp;lt;c-search value={ state.value } /&amp;gt;&lt;/code&gt;. Dans l'état, le résultat est initialisé avec des valeurs par défaut pour agir comme un "historique de recherche". La valeur par défaut de state.results peut être initialisée à partir d'une API.&lt;/li&gt;
&lt;li&gt;Si l'entrée de recherche change, deux événements &lt;code&gt;change&lt;/code&gt; et &lt;code&gt;keyup&lt;/code&gt; sont déclenchés : la fonction &lt;code&gt;changed&lt;/code&gt; est exécutée pour mettre à jour &lt;code&gt;state.value&lt;/code&gt;, et pour rafraîchir la liste des résultats.&lt;/li&gt;
&lt;li&gt;La liste &lt;code&gt;state.results&lt;/code&gt; prend une liste filtrée de fruits ; cependant, dans une application de production, le résultat peut être calculé à partir d'un serveur/DB et retourné par une requête HTTP API.&lt;/li&gt;
&lt;li&gt;Le résultat de la recherche est passé en tant qu'attribut du composant avec &lt;code&gt;results={ state.results }&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Si un clic se produit sur un élément de la liste : l'événement &lt;code&gt;select&lt;/code&gt; est déclenché, et la fonction &lt;code&gt;selected&lt;/code&gt; est exécutée pour définir &lt;code&gt;state.value&lt;/code&gt; sur l'élément sélectionné. &lt;u&gt;Dans une application front-end de production, vous pouvez faire un appel API, charger une page spécifique, ou exécuter toute action&lt;/u&gt;.&lt;/li&gt;
&lt;li&gt;Si l'icône &lt;code&gt;close&lt;/code&gt; est cliquée, l'événement &lt;code&gt;clear&lt;/code&gt; est émis, et la fonction &lt;code&gt;reset&lt;/code&gt; est exécutée pour effacer l'entrée et la liste des résultats avec les valeurs par défaut.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Tests du Composant de Recherche
&lt;/h2&gt;

&lt;p&gt;Il existe deux méthodes pour tester le composant de recherche, et elles sont couvertes dans deux articles différents :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/steeve/test-unitaire-de-composant-riot-avec-vitest-environnement-node-24j7"&gt;Test avec Vitest et Riot-SSR dans un environnement Node&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/steeve/test-unitaire-de-composant-riot-avec-vitest-jsdom-env-16a"&gt;Test avec Vitest dans un environnement JsDom&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Conclusion&lt;/p&gt;

&lt;p&gt;Voilà 🎉 Nous avons créé un composant de recherche Riot en utilisant des éléments Material Design avec BeerCSS. Le code source de la barre de recherche est disponible sur Github : &lt;a href="https://github.com/steevepay/riot-beercss/blob/main/components/c-search.riot" rel="noopener noreferrer"&gt;https://github.com/steevepay/riot-beercss/blob/main/components/c-search.riot&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bonne journée ! Santé 🍻&lt;/p&gt;

</description>
      <category>french</category>
      <category>riotjs</category>
      <category>frontend</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Composant Dialogue avec RiotJS</title>
      <dc:creator>Steeve</dc:creator>
      <pubDate>Mon, 05 May 2025 12:00:00 +0000</pubDate>
      <link>https://forem.com/steeve/composant-dialogue-avec-riotjs-dne</link>
      <guid>https://forem.com/steeve/composant-dialogue-avec-riotjs-dne</guid>
      <description>&lt;p&gt;Cet article traite de la création d'un composant de dialogue (Dialog) avec Riot, en utilisant le CSS Material Design BeerCSS, et de la gestion des événements de clic.&lt;/p&gt;

&lt;p&gt;Avant de commencer, assurez-vous d'avoir une application de base RiotJS, ou consultez mes articles précédents de la série.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Je suppose que vous avez une compréhension de base de Riot ; cependant, n'hésitez pas à consulter la documentation si nécessaire : &lt;a href="https://riot.js.org/documentation/" rel="noopener noreferrer"&gt;https://riot.js.org/documentation/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Le dialogue informe les utilisateurs sur une tâche spécifique et peut contenir des informations critiques, nécessiter des décisions ou impliquer plusieurs tâches. Dans un dialogue modal, l'utilisateur est interrompu et interagit avec le dialogue avant de pouvoir continuer à interagir avec le reste de l'application, par exemple en choisissant une sonnerie de téléphone:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwofakckkhlyodp12olvq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwofakckkhlyodp12olvq.png" alt="Modal example to select a phone ringtone" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Base du Composant de Dialogue
&lt;/h2&gt;

&lt;p&gt;L'objectif est de créer une application Riot avec un dialogue et d'exécuter une action si le modal est annulé ou confirmé.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjc14achpep7ww5p41s2o.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjc14achpep7ww5p41s2o.gif" alt="Display a modal when a button is clicked and close the modal when the confirm or cancel button is clicked" width="760" height="467"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Tout d'abord, créez un nouveau fichier nommé &lt;strong&gt;c-dialog.riot&lt;/strong&gt; dans le dossier des composants. Le préfixe &lt;code&gt;c-&lt;/code&gt; signifie "composant", une convention de nommage utile et une bonne pratique.&lt;/p&gt;

&lt;p&gt;Écrivez le code HTML suivant dans &lt;code&gt;./components/c-dialog.riot&lt;/code&gt; (le HTML a été trouvé dans la documentation BeerCSS):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;c-dialog&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;dialog&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"
                {props?.active ? 'active ' : null}
                {props?.blur ? 'overlay blur ' : null}
                {props?.left ? 'left ' : null}
                {props?.right ? 'right ' : null}
                {props?.top ? 'top ' : null}
                {props?.bottom ? 'bottom ' : null}
                {props?.max ? 'max ' : null}
            "&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;h5&lt;/span&gt; &lt;span class="na"&gt;if=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="err"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;title&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{ props?.title }&lt;span class="nt"&gt;&amp;lt;/h5&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
            { props?.message }
            &lt;span class="nt"&gt;&amp;lt;slot&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"body"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/slot&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;nav&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"right-align no-space"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;(ev) =&lt;/span&gt;&lt;span class="err"&gt;&amp;gt; &lt;/span&gt;&lt;span class="s"&gt;clicked(ev,&lt;/span&gt; &lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="na"&gt;cancel&lt;/span&gt;&lt;span class="err"&gt;")&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"transparent link"&lt;/span&gt; &lt;span class="na"&gt;if=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="err"&gt;!&lt;/span&gt;&lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="err"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;disableCancel&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{ props?.cancelText ?? "cancel" }&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;(ev) =&lt;/span&gt;&lt;span class="err"&gt;&amp;gt; &lt;/span&gt;&lt;span class="s"&gt;clicked(ev,&lt;/span&gt; &lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="na"&gt;confirm&lt;/span&gt;&lt;span class="err"&gt;")&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"transparent link"&lt;/span&gt; &lt;span class="na"&gt;if=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="err"&gt;!&lt;/span&gt;&lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="err"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;disableConfirm&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{ props?.confirmText ?? "confirm" }&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;slot&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/slot&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/nav&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/dialog&amp;gt;&lt;/span&gt;
       &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
        &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;clicked &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
                &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stopPropagation&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
                &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dispatchEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/c-dialog&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Source Code: &lt;a href="https://github.com/steevepay/riot-beercss/blob/main/components/c-dialog.riot" rel="noopener noreferrer"&gt;https://github.com/steevepay/riot-beercss/blob/main/components/c-dialog.riot&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Expliquons le code :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Les balises &lt;code&gt;&amp;lt;c-dialog&amp;gt;&lt;/code&gt; et &lt;code&gt;&amp;lt;/c-dialog&amp;gt;&lt;/code&gt; définissent une balise racine personnalisée, portant le même nom que le fichier. Vous devez l'écrire ; sinon, cela pourrait créer des résultats inattendus. Utiliser la balise &lt;code&gt;&amp;lt;dialog&amp;gt;&amp;lt;/dialog&amp;gt;&lt;/code&gt; comme balise racine ou redéfinir des balises HTML natives est une mauvaise pratique, donc commencer par &lt;code&gt;c-&lt;/code&gt; est un bon choix de nom.&lt;/li&gt;
&lt;li&gt;Le dialogue comporte trois sections principales :

&lt;ul&gt;
&lt;li&gt;Un titre en en-tête rempli grâce à &lt;code&gt;{props.title}&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Un message dans le corps imprimé avec &lt;code&gt;{props.message}&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Une action (call to action) avec deux boutons : &lt;code&gt;annuler&lt;/code&gt; et &lt;code&gt;confirmer&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Lorsqu'un bouton est cliqué, l'événement &lt;code&gt;click&lt;/code&gt; est capturé dans la fonction &lt;code&gt;clicked&lt;/code&gt;, puis un événement personnalisé est émis vers le HTML parent avec &lt;code&gt;this.root.dispatchEvent(new Event(name));&lt;/code&gt; : il émettra soit &lt;code&gt;confirm&lt;/code&gt; soit &lt;code&gt;cancel&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Le modal s'affiche uniquement si &lt;code&gt;props.active&lt;/code&gt; existe et est positif ; alors, la classe &lt;code&gt;active&lt;/code&gt; est appliquée.&lt;/li&gt;
&lt;li&gt;Le composant Dialogue a différents styles, et il est imprimé conditionnellement si leurs &lt;code&gt;props&lt;/code&gt; correspondants existent, par exemple pour rendre le dialogue plein écran : &lt;code&gt;{props?.max ? 'max ' : null}&lt;/code&gt; si la propriété max existe, la classe max est appliquée.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Enfin, chargez et instanciez le composant &lt;strong&gt;c-dialog.riot&lt;/strong&gt; dans une page principale nommée &lt;strong&gt;index.riot&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;index-riot&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"width:800px;padding:20px;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;c-button&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;(ev) =&lt;/span&gt;&lt;span class="err"&gt;&amp;gt; &lt;/span&gt;&lt;span class="s"&gt;update({&lt;/span&gt; &lt;span class="na"&gt;active:&lt;/span&gt; &lt;span class="err"&gt;!&lt;/span&gt;&lt;span class="na"&gt;state.active&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="na"&gt;max:&lt;/span&gt; &lt;span class="na"&gt;false&lt;/span&gt; &lt;span class="err"&gt;})}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Dialog&lt;span class="nt"&gt;&amp;lt;/c-button&amp;gt;&lt;/span&gt; 
        &lt;span class="nt"&gt;&amp;lt;c-button&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;(ev) =&lt;/span&gt;&lt;span class="err"&gt;&amp;gt; &lt;/span&gt;&lt;span class="s"&gt;update({&lt;/span&gt; &lt;span class="na"&gt;active:&lt;/span&gt; &lt;span class="err"&gt;!&lt;/span&gt;&lt;span class="na"&gt;state.active&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="na"&gt;max:&lt;/span&gt; &lt;span class="na"&gt;true&lt;/span&gt; &lt;span class="err"&gt;})}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Max&lt;span class="nt"&gt;&amp;lt;/c-button&amp;gt;&lt;/span&gt;

        &lt;span class="nt"&gt;&amp;lt;c-dialog&lt;/span&gt; 
            &lt;span class="na"&gt;title=&lt;/span&gt;&lt;span class="s"&gt;"Dialog"&lt;/span&gt; 
            &lt;span class="na"&gt;message=&lt;/span&gt;&lt;span class="s"&gt;"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."&lt;/span&gt;
            &lt;span class="na"&gt;active=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;state.active&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;oncancel=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;cancel&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; 
            &lt;span class="na"&gt;onconfirm=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;confirm&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;max=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;state.max&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;
        &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
        &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;cButton&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../components/c-button.riot&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;cDialog&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../components/c-dialog.riot&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

        &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;components&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;cDialog&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nx"&gt;cButton&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;max&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="nf"&gt;cancel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dialog cancel&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="nf"&gt;confirm&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dialog confirm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/index-riot&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Source Code: &lt;a href="https://github.com/steevepay/riot-beercss/blob/main/examples/index.dialog.riot" rel="noopener noreferrer"&gt;https://github.com/steevepay/riot-beercss/blob/main/examples/index.dialog.riot&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Détails du code :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Les composants sont importés avec &lt;code&gt;import cDialog from "./components/c-dialog.riot";&lt;/code&gt; puis chargés dans l'objet Riot &lt;code&gt;components:{}&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Le composant dialog est instancié avec &lt;code&gt;&amp;lt;c-dialog/&amp;gt;&lt;/code&gt; dans le HTML.&lt;/li&gt;
&lt;li&gt;L'état du dialogue est stocké dans l'objet Riot &lt;code&gt;state:{}&lt;/code&gt; sous la propriété booléenne &lt;code&gt;state.active&lt;/code&gt;. La propriété est passée en tant qu'attribut, comme : &lt;code&gt;&amp;lt;c-dialog active={ state.active }/&amp;gt;&lt;/code&gt;. Lorsque le bouton est cliqué, il définit la propriété &lt;code&gt;active&lt;/code&gt; sur true et affiche le modal.&lt;/li&gt;
&lt;li&gt;Le titre et le message du dialogue sont passés en tant qu'attributs.&lt;/li&gt;
&lt;li&gt;Si le bouton &lt;code&gt;annuler&lt;/code&gt; ou &lt;code&gt;confirmer&lt;/code&gt; est cliqué, il émettra deux événements personnalisés :

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;oncancel&lt;/code&gt; : il exécutera la fonction &lt;code&gt;this.cancel()&lt;/code&gt;, et fermera le modal.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;onconfirm&lt;/code&gt; : il exécutera la fonction &lt;code&gt;this.confirm()&lt;/code&gt;, et fermera le modal.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Les deux appels à l'action peuvent être liés à une fonction personnalisée : faire un appel API, ajouter un élément HTML, envoyer un email, confirmer une suppression et plus encore !&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Tests du Composant de Dialogue
&lt;/h2&gt;

&lt;p&gt;Il existe deux méthodes pour tester le composant de dialogue, et elles sont couvertes dans deux articles différents :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/steeve/test-unitaire-de-composant-riot-avec-vitest-environnement-node-24j7"&gt;Test avec Vitest et Riot-SSR dans un environnement Node&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/steeve/test-unitaire-de-composant-riot-avec-vitest-jsdom-env-16a"&gt;Test avec Vitest dans un environnement JsDom&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Voilà 🎉 Nous avons créé un composant de dialogue Riot en utilisant des éléments Material Design avec BeerCSS. Le code source du modal est disponible sur Github : &lt;a href="https://github.com/steevepay/riot-beercss/blob/main/components/c-dialog.riot" rel="noopener noreferrer"&gt;https://github.com/steevepay/riot-beercss/blob/main/components/c-dialog.riot&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bonne journée ! Santé 🍻&lt;/p&gt;

</description>
      <category>riotjs</category>
      <category>french</category>
      <category>frontend</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Composant Onglets avec Riot</title>
      <dc:creator>Steeve</dc:creator>
      <pubDate>Mon, 28 Apr 2025 12:00:00 +0000</pubDate>
      <link>https://forem.com/steeve/composant-onglets-avec-riot-39g6</link>
      <guid>https://forem.com/steeve/composant-onglets-avec-riot-39g6</guid>
      <description>&lt;p&gt;Cet article traite de la création d'un composant d'onglets (Tabs) avec Riot, en utilisant le CSS Material Design BeerCSS, et de la gestion des événements de clic. Avant de commencer, assurez-vous d'avoir une application de base Riot, ou consultez mes articles précédents.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Je suppose que vous avez une compréhension de base de Riot ; cependant, n'hésitez pas à consulter la documentation si nécessaire : &lt;a href="https://riot.js.org/documentation/" rel="noopener noreferrer"&gt;https://riot.js.org/documentation/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Les onglets sont utilisés pour organiser le contenu sur différents écrans et vues, par exemple, une application média avec 3 onglets : &lt;strong&gt;Photos&lt;/strong&gt;, &lt;strong&gt;Vidéos&lt;/strong&gt; et &lt;strong&gt;Audios&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjpikn4tcu8e4230mfwf6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjpikn4tcu8e4230mfwf6.png" alt="Application of a media center on mobile with three tabs" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Base du Composant d'Onglets
&lt;/h2&gt;

&lt;p&gt;L'objectif est de créer une application Riot avec des onglets, de changer l'onglet actif au clic, et de modifier le contenu de la page:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnsb19rf1mra9d85wh0sr.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnsb19rf1mra9d85wh0sr.gif" alt="Active Tabs changes on click event" width="1610" height="278"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Tout d'abord, créez un nouveau fichier nommé &lt;strong&gt;c-tabs.riot&lt;/strong&gt; dans le dossier des composants. Le préfixe &lt;code&gt;c-&lt;/code&gt; signifie "composant", une convention de nommage utile et une bonne pratique.&lt;/p&gt;

&lt;p&gt;Écrivez le code HTML suivant dans &lt;strong&gt;./components/c-tabs.riot&lt;/strong&gt; (CSS trouvé dans la documentation &lt;a href="https://www.beercss.com/#tabs" rel="noopener noreferrer"&gt;BeerCSS&lt;/a&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;c-tabs&amp;gt;&lt;/span&gt;
     &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"tabs
        { props?.min ? ' min' : null }
        { props?.rightAlign ? ' right-align' : null }
        { props?.centerAlign ? ' center-align' : null }
        { props?.leftAlign ? ' left-align' : null }
    "&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;each=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="na"&gt;tab&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="na"&gt;index&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt; &lt;span class="na"&gt;in&lt;/span&gt; &lt;span class="na"&gt;props.tabs&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"{ props.active === index ? 'active ' : null }{ props?.vertical ? 'vertical' : null }"&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;(ev) =&lt;/span&gt;&lt;span class="err"&gt;&amp;gt; &lt;/span&gt;&lt;span class="s"&gt;clicked(ev,&lt;/span&gt; &lt;span class="na"&gt;index&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;i&lt;/span&gt; &lt;span class="na"&gt;if=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;tab&lt;/span&gt;&lt;span class="err"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;icon&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{ tab.icon }&lt;span class="nt"&gt;&amp;lt;/i&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;if=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;tab&lt;/span&gt;&lt;span class="err"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;img&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"circle"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;tab.img&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;{ tab.label }&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
        &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;clicked &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
                &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stopPropagation&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
                &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dispatchEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
                &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dispatchEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;change&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/c-tabs&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expliquons le code :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Les balises &lt;code&gt;&amp;lt;c-tabs&amp;gt;&lt;/code&gt; et &lt;code&gt;&amp;lt;/c-tabs&amp;gt;&lt;/code&gt; définissent une balise racine personnalisée, portant le même nom que le fichier. Vous devez l'écrire ; sinon, cela pourrait créer des résultats inattendus. Utiliser la balise &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; comme balise racine ou redéfinir des balises HTML natives est une mauvaise pratique, donc commencer par &lt;code&gt;c-&lt;/code&gt; est un bon choix de nom.&lt;/li&gt;
&lt;li&gt;Une liste d'onglets doit être passée en tant qu'attribut, accessible avec &lt;code&gt;props.tabs&lt;/code&gt;. Chaque objet de la liste définira les propriétés de l'onglet : l'étiquette, une image ou une icône provenant de Google Font Icons.&lt;/li&gt;
&lt;li&gt;La liste des onglets est parcourue grâce à l'expression &lt;a href="https://riot.js.org/documentation/#loops" rel="noopener noreferrer"&gt;Each&lt;/a&gt; de Riot appliquée sur les balises HTML &lt;code&gt;&amp;lt;a&amp;gt;&amp;lt;/a&amp;gt;&lt;/code&gt;, tel que : &lt;code&gt;&amp;lt;a each={ (tab, index) in props.tabs }&amp;gt; { tab.label } &amp;lt;/a&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;L'onglet actif est défini avec la propriété &lt;code&gt;active&lt;/code&gt;, l'index de l'onglet sélectionné. Si l'index de l'onglet actuellement affiché est égal à active, la classe &lt;code&gt;active&lt;/code&gt; est appliquée à l'onglet.&lt;/li&gt;
&lt;li&gt;Si l'onglet possède une icône ou une image, il affiche l'expression de l'icône &lt;code&gt;&amp;lt;i if={ tab?.icon }&amp;gt;{ tab.icon }&amp;lt;/i&amp;gt;&lt;/code&gt;, ou une image &lt;code&gt;&amp;lt;img if={ tab?.img } class="circle" src={ tab.img }&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Lorsqu'un clic se produit sur l'un des onglets, l'index de l'onglet sélectionné est passé à la fonction &lt;code&gt;clicked&lt;/code&gt;: la fonction émettra deux événements (&lt;code&gt;change&lt;/code&gt; et &lt;code&gt;click&lt;/code&gt;) et fournira l'index sélectionné.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Enfin, chargez et instanciez le composant &lt;strong&gt;c-tabs.riot&lt;/strong&gt; dans une page nommée &lt;strong&gt;index.riot&lt;/strong&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;index-riot&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"width:800px;padding:20px;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;c-tabs&lt;/span&gt; &lt;span class="na"&gt;active=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;state.active&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;tabs=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;state.tabs&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onchange=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;changed&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"page padding { state.active === 0 ? 'active' : null}"&lt;/span&gt; &lt;span class="na"&gt;if=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;state.active =&lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;h5&amp;gt;&lt;/span&gt;Tab 1&lt;span class="nt"&gt;&amp;lt;/h5&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"page padding { state.active === 1 ? 'active' : null}"&lt;/span&gt; &lt;span class="na"&gt;if=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;state.active =&lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt; &lt;span class="err"&gt;1&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;h5&amp;gt;&lt;/span&gt;Tab 2&lt;span class="nt"&gt;&amp;lt;/h5&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"page padding { state.active === 2 ? 'active' : null}"&lt;/span&gt; &lt;span class="na"&gt;if=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;state.active =&lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt; &lt;span class="err"&gt;2&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;h5&amp;gt;&lt;/span&gt;Tab 3&lt;span class="nt"&gt;&amp;lt;/h5&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"page padding { state.active === 3 ? 'active' : null}"&lt;/span&gt; &lt;span class="na"&gt;if=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;state.active =&lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt; &lt;span class="err"&gt;3&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;h5&amp;gt;&lt;/span&gt;Tab 4&lt;span class="nt"&gt;&amp;lt;/h5&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
        &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;cTabs&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./components/c-tabs.riot&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

        &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;components&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;cTabs&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;tabs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Flights&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flight&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
                    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Travel&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;card_travel&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
                    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Explore&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;explore&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
                    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;BeerCSS&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;img&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./favicon.png&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="nf"&gt;changed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                    &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;
                &lt;span class="p"&gt;})&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/index-riot&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Détails du code :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Les composants sont importés avec &lt;code&gt;import cTabs from "./components/c-tabs.riot";&lt;/code&gt; puis chargés dans l'objet Riot &lt;code&gt;components:{}&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Le composant tabs est instancié avec &lt;code&gt;&amp;lt;c-tabs/&amp;gt;&lt;/code&gt; dans le HTML.&lt;/li&gt;
&lt;li&gt;Pour stocker des données dans un composant, elles doivent être définies dans l'objet Riot &lt;code&gt;state:{}&lt;/code&gt;. Dans notre cas, deux données sont nécessaires :

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;state.tabs&lt;/code&gt; : La liste des onglets avec des étiquettes, des icônes ou des images.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;state.active&lt;/code&gt; : L'index de l'onglet sélectionné.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Passez les états au composant Tabs en tant que props : &lt;code&gt;&amp;lt;c-tabs active={ state.active } tabs={ state.tabs } onchange={ changed } /&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Lorsque quelqu'un clique sur un onglet, l'événement de changement est déclenché, et la fonction changed est exécutée : &lt;code&gt;state.active&lt;/code&gt; obtient le nouvel index sélectionné grâce à la fonction Riot &lt;code&gt;this.update({active: ev.target.value})&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Lorsque l'index &lt;code&gt;state.active&lt;/code&gt; change, la page affichée change également avec une condition IF, tel que : &lt;code&gt;&amp;lt;div if={ state.active === 0 }&amp;gt;&amp;lt;h5&amp;gt;Onglet 1&amp;lt;/h5&amp;gt;&amp;lt;/div&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Tests du Composant d'Onglets
&lt;/h2&gt;

&lt;p&gt;Il existe deux méthodes pour tester le composant d'onglets, et elles sont couvertes dans deux articles différents :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/steeve/test-unitaire-de-composant-riot-avec-vitest-environnement-node-24j7"&gt;Test avec Vitest et Riot-SSR dans un environnement Node&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/steeve/test-unitaire-de-composant-riot-avec-vitest-jsdom-env-16a"&gt;Test avec Vitest dans un environnement JsDom&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Voilà 🎉 Nous avons créé un composant d'onglets Riot en utilisant des éléments Material Design avec BeerCSS. Le code source de l'onglet est disponible sur Github : &lt;a href="https://github.com/steevepay/riot-beercss/blob/main/components/c-tabs.riot" rel="noopener noreferrer"&gt;https://github.com/steevepay/riot-beercss/blob/main/components/c-tabs.riot&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;N'hésitez pas à commenter si vous avez des questions ou besoin d'aide concernant RiotJS.&lt;/p&gt;

&lt;p&gt;Bonne journée ! Santé 🍻&lt;/p&gt;

</description>
      <category>french</category>
      <category>riotjs</category>
      <category>frontend</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Composant Chip avec RiotJS</title>
      <dc:creator>Steeve</dc:creator>
      <pubDate>Mon, 21 Apr 2025 12:00:00 +0000</pubDate>
      <link>https://forem.com/steeve/composant-chip-avec-riotjs-20nd</link>
      <guid>https://forem.com/steeve/composant-chip-avec-riotjs-20nd</guid>
      <description>&lt;p&gt;Cet article traite de la création d'un composant Chip avec RiotJS, en utilisant le CSS Material Design BeerCSS. Avant de commencer, assurez-vous d'avoir une application de base RiotJS, ou consultez mes articles précédents.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Je suppose que vous avez une compréhension de base de Riot ; cependant, n'hésitez pas à consulter la documentation si nécessaire : &lt;a href="https://riot.js.org/documentation/" rel="noopener noreferrer"&gt;https://riot.js.org/documentation/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Les Chips aident les gens à entrer des informations, à faire des sélections, à filtrer du contenu ou à déclencher des actions (voir la capture d'écran suivante). L'objectif est de créer un composant Chip qui prend en charge tous les styles de BeerCSS et écoute les événements de clic.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkivm5ebitqk21y110jxd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkivm5ebitqk21y110jxd.png" alt="Chips example from the material.io documentation" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Base du Composant Chip
&lt;/h2&gt;

&lt;p&gt;Tout d'abord, créez un nouveau fichier nommé &lt;strong&gt;c-chip.riot&lt;/strong&gt; dans le dossier des composants. Le préfixe &lt;code&gt;c-&lt;/code&gt; signifie "composant", une convention de nommage utile et une bonne pratique.&lt;/p&gt;

&lt;p&gt;Dans &lt;strong&gt;./components/c-chip.riot&lt;/strong&gt;, écrivez le code HTML suivant (CSS trouvé dans la documentation BeerCSS):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;c-chip&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"
            chip
            {props?.small ? 'small' : null }
            {props?.medium ? 'medium' : null }
            {props?.large ? 'large' : null }

            {props?.smallElevate ? 'small-elevate' : null}
            {props?.mediumElevate ? 'medium-elevate' : null}
            {props?.largeElevate ? 'large-elevate' : null}

            {props?.round ? 'round' : null }
            {props?.fill ? 'fill' : null }
            {props?.vertical ? 'vertical' : null }
        "&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;i&lt;/span&gt; &lt;span class="na"&gt;if=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="err"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;icon&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{ props.icon }&lt;span class="nt"&gt;&amp;lt;/i&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;{props?.inline&lt;/span&gt; &lt;span class="err"&gt;?&lt;/span&gt; &lt;span class="na"&gt;null&lt;/span&gt; &lt;span class="na"&gt;:&lt;/span&gt; &lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="na"&gt;responsive&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;if=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="err"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;img&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;props.img&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&amp;lt;slot&amp;gt;&amp;lt;/slot&amp;gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;i&lt;/span&gt; &lt;span class="na"&gt;if=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="err"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;iconend&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{ props.iconend }&lt;span class="nt"&gt;&amp;lt;/i&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/c-chip&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expliquons le code :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Les balises &lt;code&gt;&amp;lt;c-chip&amp;gt;&lt;/code&gt; et &lt;code&gt;&amp;lt;/c-chip&amp;gt;&lt;/code&gt; définissent une balise racine personnalisée, portant le même nom que le fichier. Vous devez l'écrire ; sinon, cela pourrait créer des résultats inattendus. Utiliser la balise &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; comme balise racine ou redéfinir des balises HTML natives est une mauvaise pratique, donc commencer par &lt;code&gt;c-&lt;/code&gt; est un bon choix de nom.&lt;/li&gt;
&lt;li&gt;En utilisant la balise &lt;code&gt;&amp;lt;slot&amp;gt;&lt;/code&gt;, vous pouvez injecter des modèles HTML personnalisés dans un composant enfant depuis son parent : nous allons injecter l'étiquette du chip.&lt;/li&gt;
&lt;li&gt;Un chip a de nombreuses classes de variations : taille, élévation et forme (rond, rempli ou vertical). Elles sont injectées conditionnellement si les propriétés correspondantes existent. Par exemple, si la propriété &lt;code&gt;props.round&lt;/code&gt; existe, elle activera la classe round dans le composant.&lt;/li&gt;
&lt;li&gt;Deux icônes peuvent être passées à deux positions : soit comme préfixe, soit comme suffixe du label:

&lt;ul&gt;
&lt;li&gt;la propriété &lt;code&gt;icon&lt;/code&gt; injecte le glyphe avant l'étiquette&lt;/li&gt;
&lt;li&gt;la propriété &lt;code&gt;iconend&lt;/code&gt; injecte le glyphe après l'étiquette&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Grâce à la propriété img, une image peut être injectée à la place d'une icône.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Enfin, le composant &lt;strong&gt;c-chip.riot&lt;/strong&gt; peut être instancié dans une page &lt;strong&gt;index.riot&lt;/strong&gt;. Voici toutes les variations de Chip, qu'elles soient remplies, arrondies, incluant une image ou une icône :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;index-riot&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"width:800px;padding:20px;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;h4&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"margin-bottom:20px;margin-left:10px;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Riot + BeerCSS&lt;span class="nt"&gt;&amp;lt;/h4&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;h6&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"margin-left:10px"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Chip Variations&lt;span class="nt"&gt;&amp;lt;/h6&amp;gt;&amp;lt;br&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;c-chip&amp;gt;&lt;/span&gt;Suggestion&lt;span class="nt"&gt;&amp;lt;/c-chip&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;c-chip&lt;/span&gt; &lt;span class="na"&gt;iconend=&lt;/span&gt;&lt;span class="s"&gt;"close"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Input&lt;span class="nt"&gt;&amp;lt;/c-chip&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;c-chip&lt;/span&gt; &lt;span class="na"&gt;icon=&lt;/span&gt;&lt;span class="s"&gt;"check"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;filter&lt;span class="nt"&gt;&amp;lt;/c-chip&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;c-chip&lt;/span&gt; &lt;span class="na"&gt;icon=&lt;/span&gt;&lt;span class="s"&gt;"today"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;assist&lt;span class="nt"&gt;&amp;lt;/c-chip&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;c-chip&lt;/span&gt; &lt;span class="na"&gt;img=&lt;/span&gt;&lt;span class="s"&gt;"./favicon.png"&lt;/span&gt; &lt;span class="na"&gt;inline=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;image&lt;span class="nt"&gt;&amp;lt;/c-chip&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;c-chip&lt;/span&gt; &lt;span class="na"&gt;img=&lt;/span&gt;&lt;span class="s"&gt;"./favicon.png"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;image&lt;span class="nt"&gt;&amp;lt;/c-chip&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;c-chip&lt;/span&gt; &lt;span class="na"&gt;round=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Suggestion&lt;span class="nt"&gt;&amp;lt;/c-chip&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;c-chip&lt;/span&gt; &lt;span class="na"&gt;round=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;iconend=&lt;/span&gt;&lt;span class="s"&gt;"close"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Input&lt;span class="nt"&gt;&amp;lt;/c-chip&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;c-chip&lt;/span&gt; &lt;span class="na"&gt;round=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;icon=&lt;/span&gt;&lt;span class="s"&gt;"check"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;filter&lt;span class="nt"&gt;&amp;lt;/c-chip&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;c-chip&lt;/span&gt; &lt;span class="na"&gt;round=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;icon=&lt;/span&gt;&lt;span class="s"&gt;"today"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;assist&lt;span class="nt"&gt;&amp;lt;/c-chip&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;c-chip&lt;/span&gt; &lt;span class="na"&gt;round=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;img=&lt;/span&gt;&lt;span class="s"&gt;"./favicon.png"&lt;/span&gt; &lt;span class="na"&gt;inline=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;image&lt;span class="nt"&gt;&amp;lt;/c-chip&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;c-chip&lt;/span&gt; &lt;span class="na"&gt;round=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;img=&lt;/span&gt;&lt;span class="s"&gt;"./favicon.png"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;image&lt;span class="nt"&gt;&amp;lt;/c-chip&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;c-chip&lt;/span&gt; &lt;span class="na"&gt;fill=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Suggestion&lt;span class="nt"&gt;&amp;lt;/c-chip&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;c-chip&lt;/span&gt; &lt;span class="na"&gt;fill=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;iconend=&lt;/span&gt;&lt;span class="s"&gt;"close"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Input&lt;span class="nt"&gt;&amp;lt;/c-chip&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;c-chip&lt;/span&gt; &lt;span class="na"&gt;fill=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;icon=&lt;/span&gt;&lt;span class="s"&gt;"check"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;filter&lt;span class="nt"&gt;&amp;lt;/c-chip&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;c-chip&lt;/span&gt; &lt;span class="na"&gt;fill=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;icon=&lt;/span&gt;&lt;span class="s"&gt;"today"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;assist&lt;span class="nt"&gt;&amp;lt;/c-chip&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;c-chip&lt;/span&gt; &lt;span class="na"&gt;fill=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;img=&lt;/span&gt;&lt;span class="s"&gt;"./favicon.png"&lt;/span&gt; &lt;span class="na"&gt;inline=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;image&lt;span class="nt"&gt;&amp;lt;/c-chip&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;c-chip&lt;/span&gt; &lt;span class="na"&gt;fill=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;img=&lt;/span&gt;&lt;span class="s"&gt;"./favicon.png"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;image&lt;span class="nt"&gt;&amp;lt;/c-chip&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;c-chip&lt;/span&gt; &lt;span class="na"&gt;fill=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;round=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Suggestion&lt;span class="nt"&gt;&amp;lt;/c-chip&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;c-chip&lt;/span&gt; &lt;span class="na"&gt;fill=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;round=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;iconend=&lt;/span&gt;&lt;span class="s"&gt;"close"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Input&lt;span class="nt"&gt;&amp;lt;/c-chip&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;c-chip&lt;/span&gt; &lt;span class="na"&gt;fill=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;round=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;icon=&lt;/span&gt;&lt;span class="s"&gt;"check"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;filter&lt;span class="nt"&gt;&amp;lt;/c-chip&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;c-chip&lt;/span&gt; &lt;span class="na"&gt;fill=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;round=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;icon=&lt;/span&gt;&lt;span class="s"&gt;"today"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;assist&lt;span class="nt"&gt;&amp;lt;/c-chip&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;c-chip&lt;/span&gt; &lt;span class="na"&gt;fill=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;round=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;img=&lt;/span&gt;&lt;span class="s"&gt;"./favicon.png"&lt;/span&gt; &lt;span class="na"&gt;inline=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;image&lt;span class="nt"&gt;&amp;lt;/c-chip&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;c-chip&lt;/span&gt; &lt;span class="na"&gt;fill=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;round=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;img=&lt;/span&gt;&lt;span class="s"&gt;"./favicon.png"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;image&lt;span class="nt"&gt;&amp;lt;/c-chip&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
        &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;cChip&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./components/c-chip.riot&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

        &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;components&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;cChip&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/index-riot&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Explication du code :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Le composant est importé avec &lt;code&gt;import cChip from "./components/c-chip.riot";&lt;/code&gt; puis chargé dans l'objet Riot &lt;code&gt;components:{}&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Dans le HTML, le composant Chip est instancié avec &lt;code&gt;&amp;lt;c-chip&amp;gt;label&amp;lt;c-chip&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Passez des attributs à la balise pour activer les variations, par exemple : &lt;code&gt;&amp;lt;c-chip fill="true" round="true" icon="check"&amp;gt;filter&amp;lt;/c-chip&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Capture d'écran du HTML généré :&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmsfo8g4wh83phx41r1u4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmsfo8g4wh83phx41r1u4.png" alt="Variations of the chip Component made with RiotJS and BeerCSS" width="800" height="405"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Événements du Composant Chip
&lt;/h2&gt;

&lt;p&gt;Comme mentionné, un Chip est utilisé pour filtrer, suggérer et déclencher des actions. Un exemple concret serait que vous devez sélectionner les commodités de votre appartement pour une demande de location.&lt;/p&gt;

&lt;p&gt;Créons un groupe de chips pour chaque commodité et vérifions s'il est sélectionné.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvkn7i2hic0a10xyet25g.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvkn7i2hic0a10xyet25g.gif" alt="Chip group listening to click events" width="1028" height="272"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Voici le code Riot correspondant dans &lt;strong&gt;index.riot&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;index-riot&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"width:800px;padding:20px;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;h6&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"margin-left:10px"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Amenities&lt;span class="nt"&gt;&amp;lt;/h6&amp;gt;&amp;lt;br&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;c-chip&lt;/span&gt; &lt;span class="na"&gt;each=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;el&lt;/span&gt; &lt;span class="na"&gt;in&lt;/span&gt; &lt;span class="na"&gt;state.amenities&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;(ev) =&lt;/span&gt;&lt;span class="err"&gt;&amp;gt; &lt;/span&gt;&lt;span class="s"&gt;clicked(el.label)&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;fill=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;el.checked =&lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt; &lt;span class="na"&gt;true&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;icon=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;el.checked =&lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt; &lt;span class="na"&gt;true&lt;/span&gt; &lt;span class="err"&gt;?&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="na"&gt;check&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt; &lt;span class="na"&gt;:&lt;/span&gt; &lt;span class="na"&gt;null&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; { el.label } &lt;span class="nt"&gt;&amp;lt;/c-chip&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
        &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;cChip&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./components/c-chip.riot&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

        &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;components&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;cChip&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;amenities&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Wash / Dryer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
                    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Ramp Access&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
                    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Garden&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
                    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Cat OK&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="nf"&gt;clicked &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;_el&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;amenities&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_el&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nx"&gt;_el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;checked&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;_el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/index-riot&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Détails du code :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Une liste de Chips est imprimée grâce à l'attribut &lt;a href="https://riot.js.org/documentation/#loops" rel="noopener noreferrer"&gt;Each&lt;/a&gt; de Riot.&lt;/li&gt;
&lt;li&gt;Chaque chip écoute un événement de clic avec &lt;code&gt;onclick={ (ev) =&amp;gt; clicked(el.label) }&lt;/code&gt;. Si un événement de clic est déclenché, la fonction &lt;code&gt;clicked&lt;/code&gt; est exécutée, et le label est passée comme premier argument.&lt;/li&gt;
&lt;li&gt;La fonction &lt;code&gt;clicked&lt;/code&gt; trouve l'élément de la liste en fonction de l'étiquette, puis la propriété &lt;code&gt;checked&lt;/code&gt; est mise à jour.&lt;/li&gt;
&lt;li&gt;Lorsque &lt;code&gt;checked&lt;/code&gt; est vrai (true), deux attributs sont activés : &lt;code&gt;fill&lt;/code&gt; et &lt;code&gt;icon&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Tests du Composant Chip
&lt;/h2&gt;

&lt;p&gt;Il existe deux méthodes pour tester le composant Chip, et elles sont couvertes dans deux articles différents :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/steeve/test-unitaire-de-composant-riot-avec-vitest-environnement-node-24j7"&gt;Test avec Vitest et Riot-SSR dans un environnement Node&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/steeve/test-unitaire-de-composant-riot-avec-vitest-jsdom-env-16a"&gt;Test avec Vitest dans un environnement JsDom&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Voilà 🎉 Nous avons créé un composant Chip Riot en utilisant des éléments Material Design avec BeerCSS. &lt;/p&gt;

&lt;p&gt;Le code source du chip est disponible sur Github : &lt;a href="https://github.com/steevepay/riot-beercss/blob/main/components/c-chip.riot" rel="noopener noreferrer"&gt;https://github.com/steevepay/riot-beercss/blob/main/components/c-chip.riot&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;N'hésitez pas à commenter si vous avez des questions ou besoin d'aide concernant RiotJS.&lt;/p&gt;

&lt;p&gt;Bonne journée ! Santé 🍻&lt;/p&gt;

</description>
      <category>riotjs</category>
      <category>french</category>
      <category>javascript</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Composant Table avec RiotJS</title>
      <dc:creator>Steeve</dc:creator>
      <pubDate>Mon, 14 Apr 2025 12:00:00 +0000</pubDate>
      <link>https://forem.com/steeve/composant-table-avec-riotjs-3807</link>
      <guid>https://forem.com/steeve/composant-table-avec-riotjs-3807</guid>
      <description>&lt;p&gt;Cet article traite de la création d'un composant Table avec RiotJS, en utilisant BeerCSS. Avant de commencer, assurez-vous d'avoir une application de base RiotJS, ou lisez mes articles précédents.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;n'hésitez pas à consulter la documentation de Riot si nécessaire : &lt;a href="https://riot.js.org/documentation/" rel="noopener noreferrer"&gt;https://riot.js.org/documentation/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Une Table est un élément complexe et riche avec de nombreux styles et actions. L'article vise à créer un composant Table avec un design BeerCSS, affichant une liste d'objets. Ensuite, personnalisez les cellules avec des éléments spéciaux (chips, cases à cocher, etc.).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frerh2258tkbluwubizbm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frerh2258tkbluwubizbm.png" alt="Table Component made with RiotJS and BeerCSS" width="800" height="344"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Base du composant Table
&lt;/h2&gt;

&lt;p&gt;Tout d'abord, créez un nouveau fichier nommé &lt;strong&gt;c-table.riot&lt;/strong&gt; dans le dossier des composants. Le préfixe &lt;code&gt;c-&lt;/code&gt; signifie "composant", une convention de nommage utile et une bonne pratique.&lt;/p&gt;

&lt;p&gt;Écrivez le code HTML suivant dans &lt;code&gt;./components/c-table.riot&lt;/code&gt; (le CSS a été trouvé dans la documentation BeerCSS):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;c-table&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;table&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"
                { props?.leftAlign ? 'left-align ' : null }
                { props?.centerAlign ? 'center-align ' : null }
                { props?.rightAlign ? 'right-align ' : null }
                { props?.stripes ? 'stripes ' : null }
                { props?.outlined ? 'border ' : null }
                { props?.scroll ? 'scroll' : null }"&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;thead&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"{props?.scroll ? ' fixed' : null }"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;tr&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;th&lt;/span&gt; &lt;span class="na"&gt;each=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;col&lt;/span&gt; &lt;span class="na"&gt;in&lt;/span&gt; &lt;span class="na"&gt;Object.keys&lt;/span&gt;&lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="err"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="err"&gt;?.[0])}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{ col }&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/thead&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;tbody&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;tr&lt;/span&gt; &lt;span class="na"&gt;each=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;item&lt;/span&gt; &lt;span class="na"&gt;in&lt;/span&gt; &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="err"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;td&lt;/span&gt; &lt;span class="na"&gt;if=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;item&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;each=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;val&lt;/span&gt; &lt;span class="na"&gt;in&lt;/span&gt; &lt;span class="na"&gt;Object.values&lt;/span&gt;&lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="na"&gt;item&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                    { val }
                &lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/tbody&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;tfoot&lt;/span&gt; &lt;span class="na"&gt;if=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="na"&gt;.footer =&lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt; &lt;span class="na"&gt;true&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"{props?.scroll ? ' fixed' : null }"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;tr&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;th&lt;/span&gt; &lt;span class="na"&gt;each=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;header&lt;/span&gt; &lt;span class="na"&gt;in&lt;/span&gt; &lt;span class="na"&gt;Object.keys&lt;/span&gt;&lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="err"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="err"&gt;?.[0])}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{ header }&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/tfoot&amp;gt;&lt;/span&gt; 
    &lt;span class="nt"&gt;&amp;lt;/table&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;thead&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;tfoot&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;tr&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="nd"&gt;::first-letter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nl"&gt;text-transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nb"&gt;capitalize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/c-table&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Décomposons le code :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Les balises &lt;code&gt;&amp;lt;c-table&amp;gt;&lt;/code&gt; et &lt;code&gt;&amp;lt;/c-table&amp;gt;&lt;/code&gt; définissent une balise racine personnalisée, portant le même nom que le fichier. Vous devez l'écrire ; sinon, cela pourrait créer des résultats inattendus. Utiliser la balise &lt;code&gt;&amp;lt;label&amp;gt;&lt;/code&gt; comme balise racine ou redéfinir des balises HTML natives est une mauvaise pratique, donc commencer par &lt;code&gt;c-&lt;/code&gt; est un bon nommage.&lt;/li&gt;
&lt;li&gt;Le composant peut recevoir une liste d'objets items en tant qu'attribut, et peut être utilisé dans le composant avec &lt;code&gt;props?.items&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Pour créer des cellules, l'expression Riot &lt;a href="https://riot.js.org/documentation/#loops" rel="noopener noreferrer"&gt;each&lt;/a&gt; est utilisée pour parcourir les éléments :

&lt;ul&gt;
&lt;li&gt;Une première boucle est utilisée pour chaque balise de ligne de tableau avec &lt;code&gt;&amp;lt;tr each={ item in props?.items}&amp;gt;&lt;/code&gt;. L'item est un objet de la liste.&lt;/li&gt;
&lt;li&gt;Une deuxième boucle enfant est utilisée pour chaque cellule de tableau avec &lt;code&gt;&amp;lt;td if={ item } each={ val in Object.values(item) }&amp;gt;{ val }&amp;lt;/td&amp;gt;&lt;/code&gt;. L'expression &lt;code&gt;Object.values()&lt;/code&gt; renvoie un tableau des valeurs d'un objet donné.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Pour l'en-tête du tableau, il utilise les noms de &lt;code&gt;key&lt;/code&gt; du premier élément de la liste &lt;code&gt;props.items&lt;/code&gt; : La fonction &lt;code&gt;Object.keys&lt;/code&gt; est utilisée pour renvoyer un tableau de toutes les clés d'objet de l'élément donné, comme &lt;code&gt;&amp;lt;th each={ col in Object.keys(props?.items?.[0])}&amp;gt;{ col }&amp;lt;/th&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;BeerCSS permet la création d'un pied de page, qui suit la même logique que l'en-tête : accéder au premier élément de la liste, obtenir une liste de clés avec &lt;code&gt;Object.keys&lt;/code&gt; et créer une boucle avec l'expression Riot each. Le pied de page est affiché conditionnellement si la propriété &lt;code&gt;props.footer&lt;/code&gt; existe.&lt;/li&gt;
&lt;li&gt;La première lettre de chaque en-tête est capitalisée grâce à l'expression CSS : &lt;code&gt;th::first-letter { text-transform:capitalize; }&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Enfin, BeerCSS fournit des classes utiles pour changer le style du tableau, par exemple, ajouter des rayures ou des bordures ou changer l'alignement. Les classes sont injectées conditionnellement avec l'expression Riot : &lt;code&gt;{ props?.stripes ? 'stripes ' : null }&lt;/code&gt; signifiant que si la propriété &lt;code&gt;props.stripes&lt;/code&gt; existe, la classe &lt;code&gt;stripes&lt;/code&gt; est ajoutée.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Enfin, chargez et instanciez le &lt;strong&gt;c-table.riot&lt;/strong&gt; dans une page nommée &lt;strong&gt;index.riot&lt;/strong&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;index-riot&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"width:800px;padding:20px;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;h4&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"margin-bottom:20px"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Riot + BeerCSS&lt;span class="nt"&gt;&amp;lt;/h4&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;c-table&lt;/span&gt; &lt;span class="na"&gt;items=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;state.animals&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
        &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;cTable&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./components/c-table-full.riot&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

        &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;components&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;cTable&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;animals&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                    &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;African Elephant&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;species&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Loxodonta africana&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;diet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Herbivore&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;habitat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Savanna, Forests&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
                    &lt;span class="p"&gt;},&lt;/span&gt;
                    &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Lion&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;species&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Panthera leo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;diet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Carnivore&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;habitat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Savanna, Grassland&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
                    &lt;span class="p"&gt;},&lt;/span&gt;
                    &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hippopotamus&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;species&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hippopotamus amphibius&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;diet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Herbivore&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;habitat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Riverbanks, Lakes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/index-riot&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Détails du code :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Les composants sont importés avec &lt;code&gt;import cTable from "./components/c-table.riot";&lt;/code&gt; puis chargés dans l'objet Riot &lt;code&gt;components:{}&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Le tableau est instancié avec &lt;code&gt;&amp;lt;c-table/&amp;gt;&lt;/code&gt; dans le HTML.&lt;/li&gt;
&lt;li&gt;Une liste d'animaux est fournie au tableau, grâce à l'attribut items : &lt;code&gt;items={ state.animals } ;&lt;/code&gt; le tableau créera automatiquement les en-têtes, les lignes et les cellules ! ✅&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Voici le HTML généré :&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fosxdf4y6cba4acpzhqa2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fosxdf4y6cba4acpzhqa2.png" alt="Table component made with RiotJS displaying a list of objects" width="800" height="283"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Composant Table avec cellules personnalisées
&lt;/h2&gt;

&lt;p&gt;Afficher des composants personnalisés dans les cellules est souvent nécessaire pour les applications de production, comme des cases à cocher, ou même des boutons.&lt;/p&gt;

&lt;p&gt;Cette capacité est activée grâce aux &lt;a href="https://riot.js.org/documentation/#slots" rel="noopener noreferrer"&gt;Slots&lt;/a&gt;: La balise &lt;code&gt;&amp;lt;slot&amp;gt;&lt;/code&gt; injecte des modèles HTML personnalisés dans un composant enfant depuis son parent. Modifions la boucle suivante dans &lt;code&gt;c-table.riot&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;td&lt;/span&gt; &lt;span class="na"&gt;each=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;val&lt;/span&gt; &lt;span class="na"&gt;in&lt;/span&gt; &lt;span class="na"&gt;Object.values&lt;/span&gt;&lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="na"&gt;item&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  { val }
&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remplacez-la par l'expression suivante :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;td&lt;/span&gt; &lt;span class="na"&gt;each=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;el&lt;/span&gt; &lt;span class="na"&gt;in&lt;/span&gt; &lt;span class="na"&gt;Object.entries&lt;/span&gt;&lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="na"&gt;item&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;slot&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"item"&lt;/span&gt; &lt;span class="na"&gt;item=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;item&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;column=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;el&lt;/span&gt;&lt;span class="err"&gt;?.[0]&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;el&lt;/span&gt;&lt;span class="err"&gt;?.[1]&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/slot&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;if=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;slots.length =&lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      { el?.[1] }
   &lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expliquons ce qui se passe ici :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Au lieu d'utiliser &lt;code&gt;Object.values&lt;/code&gt;, on utilise &lt;code&gt;Object.entries&lt;/code&gt; pour convertir un objet en une liste de &lt;code&gt;[key, value]&lt;/code&gt;. Par exemple, &lt;code&gt;[{key: 1, name: "blue"}]&lt;/code&gt; renvoie &lt;code&gt;[["key", 1], ["name", "blue"]]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Un slot est créé pour chaque cellule : &lt;code&gt;&amp;lt;slot name="item" column={ el?.[0] } item={ item } value={ el?.[1] }&amp;gt;&amp;lt;/slot&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Passer des valeurs dynamiques aux slots s'appelle des &lt;a href="https://riot.js.org/api/#higher-order-components" rel="noopener noreferrer"&gt;Higher Order Components&lt;/a&gt;: Tous les attributs définis sur les balises de slot seront disponibles dans leurs modèles HTML injectés. Dans notre cas, quatre attributs sont créés :

&lt;ul&gt;
&lt;li&gt;Le slot a un nom optionnel, une convention de nommage Riot, sans le définir, il aurait le nom &lt;code&gt;default&lt;/code&gt;. &lt;a href="https://github.com/riot/riot/issues/3002" rel="noopener noreferrer"&gt;Il n'est pas possible de définir le nom dynamiquement&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;L'objet &lt;code&gt;item&lt;/code&gt; de la boucle de ligne est passé dans l'attribut &lt;code&gt;item&lt;/code&gt; du slot : Il sera accessible sur le composant passé en tant que slots !.&lt;/li&gt;
&lt;li&gt;La &lt;code&gt;clé&lt;/code&gt; de l'élément est passée à l'attribut column du slot grâce à &lt;code&gt;column={ el?.[0] }&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;La &lt;code&gt;valeur&lt;/code&gt; de l'élément est passée à l'attribut value du slot grâce à &lt;code&gt;value={ el?.[1] }&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Si le slot n'existe pas, la valeur de la cellule est imprimée avec &lt;code&gt;&amp;lt;template if={ slots.length === 0 }&amp;gt;{ el?.[1] }&amp;lt;/template&amp;gt;&lt;/code&gt;. Les directives &lt;code&gt;if&lt;/code&gt; peuvent être utilisées avec une balise &lt;code&gt;&amp;lt;template&amp;gt;&lt;/code&gt;, dans notre cas, on souhaite afficher conditonnellement la valeur de l'élément (en savoir plus &lt;a href="https://riot.js.org/documentation/#fragments-conditional" rel="noopener noreferrer"&gt;sur la documentation Riot&lt;/a&gt;).&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Maintenant, dans &lt;strong&gt;index.riot&lt;/strong&gt;, affichons un composant &lt;code&gt;Chip&lt;/code&gt; pour la colonne Diet :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;index-riot&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"width:800px;padding:20px;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;h4&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"margin-bottom:20px"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Riot + BeerCSS&lt;span class="nt"&gt;&amp;lt;/h4&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;c-table&lt;/span&gt; &lt;span class="na"&gt;items=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;state.animals&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;slot=&lt;/span&gt;&lt;span class="s"&gt;"item"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;c-chip&lt;/span&gt; &lt;span class="na"&gt;if=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;column =&lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="na"&gt;diet&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                    { value }
                &lt;span class="nt"&gt;&amp;lt;/c-chip&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;if=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;column&lt;/span&gt; &lt;span class="err"&gt;!==&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="na"&gt;diet&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                    { value }
                &lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/c-table&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
        &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;cTable&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./components/c-table-full.riot&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;cChip&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./components/c-chip.riot&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

        &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;components&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;cTable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nx"&gt;cChip&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;animals&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                    &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;African Elephant&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;species&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Loxodonta africana&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;diet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Herbivore&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;habitat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Savanna, Forests&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
                    &lt;span class="p"&gt;},&lt;/span&gt;
                    &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Lion&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;species&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Panthera leo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;diet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Carnivore&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;habitat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Savanna, Grassland&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
                    &lt;span class="p"&gt;},&lt;/span&gt;
                    &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hippopotamus&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;species&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hippopotamus amphibius&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;diet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Herbivore&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;habitat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Riverbanks, Lakes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/index-riot&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Décomposition du code :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Le composant Chip est définie dans l'objet Riot &lt;code&gt;components:{}&lt;/code&gt; puis chargée avec &lt;code&gt;&amp;lt;c-chip&amp;gt; Label &amp;lt;/c-chip&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Dès que nous utilisons &lt;code&gt;slot="item"&lt;/code&gt;, par exemple &lt;code&gt;&amp;lt;c-chip slot="item"&amp;gt;{ value }&amp;lt;/c-chip&amp;gt;&lt;/code&gt;, l'élément Chip sera injecté dans toutes les cellules. Utiliser une seule Chip comme Slot est une mauvaise idée : la Chip sera affichée pour toutes les cellules. Ce n'est pas ce que nous voulons !&lt;/li&gt;
&lt;li&gt;Grâce aux trois attributs dynamiques (magie des Higher Order Components ✨), nous pouvons contrôler ce qui est affiché :

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;item&lt;/code&gt; est l'objet pour la ligne actuelle,&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;column&lt;/code&gt; pour la clé d'en-tête actuelle,&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;value&lt;/code&gt; pour la valeur de la cellule.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Lorsque plusieurs éléments HTML sont affichés dans un slot, il est préférable de les envelopper dans une balise "template", dans notre cas : &lt;code&gt;&amp;lt;template slot="item"&amp;gt;&amp;lt;/template&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;La partie la plus importante est : &lt;code&gt;&amp;lt;c-chip if={ column === 'diet' }&amp;gt;{ value }&amp;lt;/c-chip&amp;gt;&amp;lt;template if={ column !== 'diet' }&amp;gt;{ value }&amp;lt;/template&amp;gt;&lt;/code&gt;. Si la colonne actuelle est diet, la Chip affiche la valeur, sinon, la valeur brute est affichée.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Voici le résultat HTML :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw49h2uihmioo11ll0ek3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw49h2uihmioo11ll0ek3.png" alt="Table Riot Component with custom chips components to print cells values" width="800" height="311"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Composant Table avec des cases à cocher
&lt;/h2&gt;

&lt;p&gt;Le processus d'insertion de cases à cocher dans le tableau est le même que dans la section précédente : le composant de case à cocher est passé en tant que &lt;a href="https://riot.js.org/documentation/#slots" rel="noopener noreferrer"&gt;Slot&lt;/a&gt;, et il doit être affiché en fonction d'un nom de colonne.&lt;/p&gt;

&lt;p&gt;Dans notre cas, la case à cocher obtient la valeur booléenne de la colonne &lt;code&gt;enabled&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Voici le code HTML pour &lt;strong&gt;index.riot&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;index-riot&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"width:800px;padding:20px;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;h4&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"margin-bottom:20px"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Riot + BeerCSS&lt;span class="nt"&gt;&amp;lt;/h4&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;c-table&lt;/span&gt; &lt;span class="na"&gt;items=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;state.animals&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;slot=&lt;/span&gt;&lt;span class="s"&gt;"item"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;c-checkbox&lt;/span&gt; &lt;span class="na"&gt;if=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;column =&lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onchange=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;(ev) =&lt;/span&gt;&lt;span class="err"&gt;&amp;gt; &lt;/span&gt;&lt;span class="s"&gt;changed(&lt;/span&gt; &lt;span class="na"&gt;item.id&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="na"&gt;ev.target.value&lt;/span&gt; &lt;span class="err"&gt;)&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;c-chip&lt;/span&gt; &lt;span class="na"&gt;if=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;column =&lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="na"&gt;diet&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                    { value }
                &lt;span class="nt"&gt;&amp;lt;/c-chip&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;if=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="na"&gt;column&lt;/span&gt; &lt;span class="err"&gt;!==&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="na"&gt;diet&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt; &lt;span class="err"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="na"&gt;column&lt;/span&gt; &lt;span class="err"&gt;!==&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                    { value }
                &lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/c-table&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
        &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;cTable&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./components/c-table-full.riot&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;cChip&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./components/c-chip.riot&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;cCheckbox&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./components/c-checkbox.riot&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

        &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;changed &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;_el&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;animals&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_el&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nx"&gt;_el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;enabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;components&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;cTable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nx"&gt;cChip&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nx"&gt;cCheckbox&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;animals&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                    &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;African Elephant&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;species&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Loxodonta africana&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;diet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Herbivore&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;habitat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Savanna, Forests&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
                    &lt;span class="p"&gt;},&lt;/span&gt;
                    &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Lion&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;species&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Panthera leo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;diet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Carnivore&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;habitat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Savanna, Grassland&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
                    &lt;span class="p"&gt;},&lt;/span&gt;
                    &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hippopotamus&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;species&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hippopotamus amphibius&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;diet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Herbivore&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;habitat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Riverbanks, Lakes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/index-riot&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Décomposition du code :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;La case à cocher personnalisée est définie comme un composant dans l'objet Riot &lt;code&gt;components:{}&lt;/code&gt; puis chargée avec &lt;code&gt;&amp;lt;c-checkbox/&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;La case à cocher est imprimée uniquement si la colonne actuelle est &lt;code&gt;enabled&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;La valeur de la case à cocher est définie grâce à &lt;code&gt;value={ value }&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Si un clic se produit sur la case à cocher, l'événement &lt;code&gt;change&lt;/code&gt; est émis, et la fonction &lt;code&gt;changed()&lt;/code&gt; est exécutée avec deux attributs &lt;code&gt;onchange={ (ev) =&amp;gt; changed( item.id, ev.target.value ) }&lt;/code&gt;:

&lt;ul&gt;
&lt;li&gt;La fonction obtient la valeur d'ID de l'élément comme premier argument.&lt;/li&gt;
&lt;li&gt;En tant que deuxième argument, la fonction obtient la valeur de la case à cocher.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;La fonction changed est exécutée : d'abord, l'objet actuel est trouvé grâce à l'ID de l'élément, et enfin la valeur &lt;code&gt;enabled&lt;/code&gt; est mise à jour.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Capture d'écran du tableau généré avec des cases à cocher :&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdpijojujb8lzsskhd891.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdpijojujb8lzsskhd891.png" alt="Image description" width="800" height="326"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Test du composant Table
&lt;/h2&gt;

&lt;p&gt;Il existe deux méthodes pour tester le composant Table, et elles sont couvertes dans deux articles différents :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/steeve/test-unitaire-de-composant-riot-avec-vitest-environnement-node-24j7"&gt;Test avec Vitest et Riot-SSR dans un environnement Node&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/steeve/test-unitaire-de-composant-riot-avec-vitest-jsdom-env-16a"&gt;Test avec Vitest dans un environnement JsDom&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Voilà 🎉 Nous avons créé un composant Table Riot en utilisant BeerCSS. Un tableau peut avoir beaucoup plus de fonctionnalités, et de nouveaux articles seraient nécessaires pour: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;rendre les lignes sélectionnables, &lt;/li&gt;
&lt;li&gt;créer des en-têtes personnalisés, &lt;/li&gt;
&lt;li&gt;un défilement virtuel, &lt;/li&gt;
&lt;li&gt;un tri, &lt;/li&gt;
&lt;li&gt;un filtrage, &lt;/li&gt;
&lt;li&gt;et plus encore.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Le code source du tableau est disponible sur Github : &lt;a href="https://github.com/steevepay/riot-beercss/blob/main/components/c-table.riot" rel="noopener noreferrer"&gt;https://github.com/steevepay/riot-beercss/blob/main/components/c-table.riot&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Passez une excellente journée ! Santé 🍻&lt;/p&gt;

</description>
      <category>french</category>
      <category>frontend</category>
      <category>riotjs</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
