<?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>DEV Community: Keff</title>
    <description>The latest articles on DEV Community by Keff (@nombrekeff).</description>
    <link>https://dev.to/nombrekeff</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%2F187971%2Fa5359a24-b652-46be-8898-2c5df32aa6e0.png</url>
      <title>DEV Community: Keff</title>
      <link>https://dev.to/nombrekeff</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nombrekeff"/>
    <language>en</language>
    <item>
      <title>I've FINALLY launched my Product!!</title>
      <dc:creator>Keff</dc:creator>
      <pubDate>Tue, 16 Dec 2025 15:05:47 +0000</pubDate>
      <link>https://dev.to/nombrekeff/ive-finally-launched-my-product-4am7</link>
      <guid>https://dev.to/nombrekeff/ive-finally-launched-my-product-4am7</guid>
      <description>&lt;h2&gt;
  
  
  &lt;a href="https://www.producthunt.com/products/cardboard-beta?launch=cardboard-js-web-apps-flat-packed" rel="noopener noreferrer"&gt;Cardboard.js is now on Product Hunt&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Hi everyone,&lt;/p&gt;

&lt;p&gt;After years of working on &lt;strong&gt;Cardboard.js&lt;/strong&gt;, I’ve finally launched it on &lt;strong&gt;Product Hunt&lt;/strong&gt;. This project started as a way to build small, interactive web apps &lt;em&gt;without writing HTML, JSX, or separate CSS files&lt;/em&gt; — you write everything in plain JavaScript or TypeScript and let Cardboard handle rendering and reactivity.&lt;/p&gt;

&lt;p&gt;If you’ve followed my earlier posts about building this framework, thanks for sticking around. If not, here’s a quick intro and a few snippets to show what it feels like to use.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Cardboard.js Is
&lt;/h2&gt;

&lt;p&gt;Cardboard.js is a &lt;strong&gt;lightweight reactive UI library&lt;/strong&gt; (~16 KB), focused on simplicity and performance. It provides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No HTML required&lt;/strong&gt; — you generate DOM elements with JS.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Built‑in state management&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reactive updates&lt;/strong&gt; (UI updates when state changes).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reusable components&lt;/strong&gt; and &lt;strong&gt;CSS‑in‑JS&lt;/strong&gt; style support. &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Quick Snippets
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Basic Usage
&lt;/h3&gt;

&lt;p&gt;Instead of writing HTML, you initialize the framework and define UI with JavaScript:&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;tag&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;init&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;allTags&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;@nkeff/cardboard-js&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;div&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="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;allTags&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Initialize Cardboard (defaults to &amp;lt;body&amp;gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Append elements&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;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;div&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;p&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello world!&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This creates and attaches the DOM for you without a template file — everything lives in code.&lt;/p&gt;
&lt;h3&gt;
  
  
  A Simple Reactive Counter
&lt;/h3&gt;

&lt;p&gt;Cardboard includes reactive state primitives so your UI updates automatically:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Counter&lt;/span&gt; &lt;span class="o"&gt;=&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;button&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Clicked $count times`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addStyle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;color&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;gray&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;stylesIf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;greaterThan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;red&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;clicked&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;count&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="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Mount it to the body&lt;/span&gt;
&lt;span class="nf"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;(body)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Here you define a component function that returns UI with reactive state. As &lt;code&gt;count.value&lt;/code&gt; changes, the text and styles update automatically.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why It Matters
&lt;/h2&gt;

&lt;p&gt;If you’ve worked with frameworks where you juggle templates, build steps, and lots of boilerplate, Cardboard offers a &lt;strong&gt;simpler alternative&lt;/strong&gt; where logic and UI live together in plain JavaScript or TypeScript. It’s small, fast, and doesn’t need HTML, CSS, or JSX if you don’t want them.&lt;/p&gt;
&lt;h2&gt;
  
  
  How You Can Help
&lt;/h2&gt;

&lt;p&gt;If you think this could be useful — or even just interesting — I’d love your support on Product Hunt. A visit, upvote, or comment goes a long way and helps this project get more visibility.&lt;/p&gt;

&lt;p&gt;

&lt;/p&gt;
&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
      &lt;div class="c-embed__body flex items-center justify-between"&gt;
        &lt;a href="https://www.producthunt.com/products/cardboard-beta/reviews/new" rel="noopener noreferrer" class="c-link fw-bold flex items-center"&gt;
          &lt;span class="mr-2"&gt;producthunt.com&lt;/span&gt;
          

        &lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;





&lt;p&gt;Thanks for reading — and if you try it out, I’d really like to hear what you build with it.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>devjournal</category>
      <category>watercooler</category>
      <category>product</category>
    </item>
    <item>
      <title>Might save you some headaches!</title>
      <dc:creator>Keff</dc:creator>
      <pubDate>Tue, 16 Sep 2025 11:19:33 +0000</pubDate>
      <link>https://dev.to/nombrekeff/might-save-you-some-headaches-hcc</link>
      <guid>https://dev.to/nombrekeff/might-save-you-some-headaches-hcc</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/nombrekeff/eskema-composable-ergonomic-runtime-data-validation-for-dart-done-right-2ice" class="crayons-story__hidden-navigation-link"&gt;Eskema: Composable, Ergonomic Runtime Data Validation for Dart Done Right!!&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/nombrekeff" class="crayons-avatar  crayons-avatar--l  "&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%2Fuser%2Fprofile_image%2F187971%2Fa5359a24-b652-46be-8898-2c5df32aa6e0.png" alt="nombrekeff profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/nombrekeff" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Keff
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Keff
                
              
              &lt;div id="story-author-preview-content-2838982" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/nombrekeff" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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%2Fuser%2Fprofile_image%2F187971%2Fa5359a24-b652-46be-8898-2c5df32aa6e0.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Keff&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/nombrekeff/eskema-composable-ergonomic-runtime-data-validation-for-dart-done-right-2ice" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Sep 11 '25&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/nombrekeff/eskema-composable-ergonomic-runtime-data-validation-for-dart-done-right-2ice" id="article-link-2838982"&gt;
          Eskema: Composable, Ergonomic Runtime Data Validation for Dart Done Right!!
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag crayons-tag--filled  " href="/t/showdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;showdev&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/programming"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;programming&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/dart"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;dart&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/flutter"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;flutter&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/nombrekeff/eskema-composable-ergonomic-runtime-data-validation-for-dart-done-right-2ice" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;11&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/nombrekeff/eskema-composable-ergonomic-runtime-data-validation-for-dart-done-right-2ice#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              &lt;span class="hidden s:inline"&gt;Add Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            4 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>programming</category>
      <category>showdev</category>
      <category>dart</category>
      <category>flutter</category>
    </item>
    <item>
      <title>Eskema: Composable, Ergonomic Runtime Data Validation for Dart Done Right!!</title>
      <dc:creator>Keff</dc:creator>
      <pubDate>Thu, 11 Sep 2025 11:53:38 +0000</pubDate>
      <link>https://dev.to/nombrekeff/eskema-composable-ergonomic-runtime-data-validation-for-dart-done-right-2ice</link>
      <guid>https://dev.to/nombrekeff/eskema-composable-ergonomic-runtime-data-validation-for-dart-done-right-2ice</guid>
      <description>&lt;p&gt;Every Dart project has &lt;em&gt;that one file&lt;/em&gt; — you know the one.&lt;br&gt;&lt;br&gt;
The file full of &lt;code&gt;if (value == null || value is! String || value.isEmpty)&lt;/code&gt; checks.&lt;br&gt;&lt;br&gt;
The file that starts out as “quick validation” and slowly mutates into a plate of spaghetti code that nobody dares to touch. 🍝&lt;/p&gt;

&lt;p&gt;I’ve been there. In fact, that’s what pushed me to build &lt;strong&gt;&lt;a href="https://github.com/nombrekeff/eskema" rel="noopener noreferrer"&gt;Eskema&lt;/a&gt;&lt;/strong&gt;.  &lt;/p&gt;

&lt;p&gt;Most existing solutions I found leaned on &lt;strong&gt;code generation&lt;/strong&gt;, which meant I ended up with opinionated, hard-to-read boilerplate and mysterious generated classes. I wanted something else: a library that was &lt;strong&gt;declarative, ergonomic, and unopinionated&lt;/strong&gt;. Something that makes it obvious &lt;em&gt;what&lt;/em&gt; is being validated and &lt;em&gt;where&lt;/em&gt; it’s happening, without sprinkling spaghetti across my codebase.  &lt;/p&gt;

&lt;p&gt;Eskema started as a tiny functional library a few years ago, but it has since grown up: now it has a solid class-based core, operator sugar, and a builder API. It’s still extremely simple to extend; adding a new validator or transformer is basically trivial, but it’s powerful enough to cover most real-world validation needs.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Eskema?
&lt;/h2&gt;

&lt;p&gt;Key features of Eskema include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Composable API:&lt;/strong&gt; Validators are just Dart functions that take a value and return a &lt;code&gt;Result&lt;/code&gt;. You can nest and combine them freely (with &lt;code&gt;all()&lt;/code&gt;, &lt;code&gt;or()&lt;/code&gt;, or the overloaded &lt;code&gt;&amp;amp;&lt;/code&gt;/&lt;code&gt;|&lt;/code&gt; operators). This makes validation logic highly composable and easy to reason about. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Rich built-in validators:&lt;/strong&gt; Out of the box, Eskema has checks for types, numbers, strings, lists, maps, etc. For example, &lt;code&gt;isString()&lt;/code&gt;, &lt;code&gt;isInt()&lt;/code&gt;, &lt;code&gt;isEmail()&lt;/code&gt;, &lt;code&gt;listEach()&lt;/code&gt;, &lt;code&gt;listIsOfLength()&lt;/code&gt;, and many more. Presence checks (&lt;code&gt;isNotNull()&lt;/code&gt;, &lt;code&gt;isNotEmpty()&lt;/code&gt;, &lt;code&gt;isPresent()&lt;/code&gt;) and comparison checks (&lt;code&gt;isGt()&lt;/code&gt;, &lt;code&gt;isLte()&lt;/code&gt;, &lt;code&gt;isIn()&lt;/code&gt;, etc.) are included too.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Operator sugar:&lt;/strong&gt; Combine validators with &lt;code&gt;&amp;amp;&lt;/code&gt; (AND) and &lt;code&gt;|&lt;/code&gt; (OR), and invert with &lt;code&gt;not()&lt;/code&gt;. For example, instead of &lt;code&gt;all([isString(), isNotEmpty()])&lt;/code&gt;, you can simply write &lt;code&gt;$isString &amp;amp; isNotEmpty()&lt;/code&gt;. You can also override error messages inline with the &lt;code&gt;&amp;gt;&lt;/code&gt; operator, e.g. &lt;code&gt;hasLength(5) &amp;gt; 'must be 5 chars'&lt;/code&gt;.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Optional vs Nullable semantics:&lt;/strong&gt; By default, a key must be present and non-null. Use &lt;code&gt;nullable(validator)&lt;/code&gt; to allow a field to be &lt;code&gt;null&lt;/code&gt;, or &lt;code&gt;optional(validator)&lt;/code&gt; to allow it to be missing entirely. This helps avoid the common confusion between “no value” and “null value.”  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Builder API:&lt;/strong&gt; If you prefer a more fluent, type-safe style, Eskema offers a builder API. For example:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;userValidator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;$map&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="s"&gt;'id'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;$string&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toIntStrict&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;gt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="s"&gt;'email'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;$string&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="s"&gt;'age'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;$string&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toIntStrict&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;gte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;optional&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;&lt;p&gt;&lt;strong&gt;No codegen&lt;/strong&gt; – all runtime: Eskema validates plain Dart maps and values at runtime. No build steps, no generated classes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Production-ready&lt;/strong&gt;: Fully tested, documented, and with sensible error messages. Failures produce a structured list of expectations (message, field path, etc.), not just a bool.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Functional Validation Examples&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Here’s a validator for a user object using the functional API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;userSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;eskema&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="s"&gt;'username'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;isString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;isNotEmpty&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="s"&gt;'password'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;isString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;hasLength&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="s"&gt;'email'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;isString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;isEmail&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="s"&gt;'signupDate'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;optional&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isDateTime&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;userSchema&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="s"&gt;'username'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'alice'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="s"&gt;'password'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'secret123'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="s"&gt;'email'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'alice@example.com'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;// signupDate omitted is OK (optional)&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="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isValid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;expectations&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;p&gt;Each field maps to a validator. We combined checks with &amp;amp; instead of writing &lt;code&gt;all([...])&lt;/code&gt;, and used &lt;code&gt;optional(isDateTime())&lt;/code&gt; to allow signupDate to be missing. The Result object has &lt;code&gt;.isValid&lt;/code&gt; and &lt;code&gt;.expectations&lt;/code&gt; with detailed error info.&lt;/p&gt;

&lt;p&gt;If you only need to validate a single value:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;isNonEmptyStr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;isString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;isNotEmpty&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isNonEmptyStr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isValid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'hello'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;          &lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isNonEmptyStr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isValid&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;      &lt;span class="c1"&gt;// false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Writing custom validators is easy too:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;Validator&lt;/span&gt; &lt;span class="n"&gt;isEven&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Validator&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&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;return&lt;/span&gt; &lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nl"&gt;isValid:&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;expected:&lt;/span&gt; &lt;span class="s"&gt;'even integer'&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Before vs After Eskema
&lt;/h2&gt;

&lt;p&gt;Let’s be honest: we’ve all written validation code like this at some point:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Before: classic if/else soup&lt;/span&gt;
&lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;validateUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;dynamic&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;user&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="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'username'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'username'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'username'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isEmpty&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="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="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'password'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'password'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="kt"&gt;String&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="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="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'password'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'password'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;32&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="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="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'email'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'email'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="kt"&gt;String&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="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="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'email'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;emailRegex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RegExp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sx"&gt;r'^[^@]+@[^@]+\.[^@]+'&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="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;emailRegex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hasMatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&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="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="k"&gt;return&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Not only is this verbose, but it’s brittle: hard to extend, hard to read, and easy to get wrong.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now here’s the same logic expressed with Eskema:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="c1"&gt;// After: Eskema&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;userSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;eskema&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="s"&gt;'username'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;isString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;isNotEmpty&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="s"&gt;'password'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;isString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;hasLength&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="s"&gt;'email'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;isString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;isEmail&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;userSchema&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="s"&gt;'username'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'alice'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="s"&gt;'password'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'secret123'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="s"&gt;'email'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'alice@example.com'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isValid&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Clean, declarative, and composable. Instead of juggling if/else and regex checks, you just describe what you expect — and Eskema takes care of the rest.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Using the Builder&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;For those who like a fluent, IDE-friendly approach, Eskema’s builder API provides similar power with method chaining:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt; &lt;em&gt;that everything is a validator, so you can combine and compose functional and builder validators.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;mapValidator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;$map&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="s"&gt;'id'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;$string&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toIntStrict&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;gt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="s"&gt;'tags'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;$list&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;each&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;$string&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lengthMin&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="c1"&gt;// Usage:&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mapValidator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="s"&gt;'id'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'42'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'tags'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'dart'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'eskema'&lt;/span&gt;&lt;span class="p"&gt;]});&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isValid&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This yields the same result as manual validators, but in a fluent syntax. The advantage lies in ergonomics: IDE autocompletion, type safety, and the elimination of the need to import numerous free functions.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Ergonomics and Tips&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Use the &lt;code&gt;$&lt;/code&gt; shortcuts: Many zero-arg validators have a cached alias. For example, &lt;code&gt;$isString&lt;/code&gt; is a pre-built &lt;code&gt;isString()&lt;/code&gt;. Looks clean and avoids re-allocating functions. Use &lt;code&gt;isString()&lt;/code&gt; if you want to specify a custom error message.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Operator overloading: Get comfortable with &lt;code&gt;&amp;amp;&lt;/code&gt;, &lt;code&gt;|&lt;/code&gt; and &lt;code&gt;not()&lt;/code&gt;. They make schemas terser and more logical to read.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Clear error messages: Use &lt;code&gt;&amp;gt;&lt;/code&gt; to override messages, &lt;em&gt;e.g. &lt;code&gt;hasLength(5) &amp;gt; Expectation(...)&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;No boilerplate: Works out of the box for Flutter forms, API handlers, config files – anywhere you need validation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Async support: Need async checks? Just use &lt;code&gt;.validateAsync()&lt;/code&gt;. Eskema will promote validators to async as needed.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Eskema takes the headache out of runtime validation by providing a simple and flexible toolkit. It’s small in scope but big in composability. You can validate nested JSON, lists, or individual values with clear syntax and rich error reporting – all without codegen or ceremony.&lt;/p&gt;

&lt;p&gt;If your app deals with dynamic data, give Eskema a try. A few ergonomic validators might just save you from a world of edge-case bugs – and maybe even a little coding despair.&lt;/p&gt;

&lt;p&gt;👉 Give it a spin: &lt;a href="https://github.com/nombrekeff/eskema" rel="noopener noreferrer"&gt;Eskema on GitHub&lt;/a&gt;. Your future self (and your teammates) will thank you.”&lt;/p&gt;

</description>
      <category>programming</category>
      <category>showdev</category>
      <category>dart</category>
      <category>flutter</category>
    </item>
    <item>
      <title>In case you're in the same situation I was in, take a read about my experience!</title>
      <dc:creator>Keff</dc:creator>
      <pubDate>Wed, 02 Jul 2025 12:38:14 +0000</pubDate>
      <link>https://dev.to/nombrekeff/in-case-youre-in-the-same-situation-i-was-in-take-a-read-about-my-experience-4pdh</link>
      <guid>https://dev.to/nombrekeff/in-case-youre-in-the-same-situation-i-was-in-take-a-read-about-my-experience-4pdh</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/nombrekeff/rediscovering-my-passion-from-burnout-back-to-excitement-cp5" class="crayons-story__hidden-navigation-link"&gt;Rediscovering My Passion: From Burnout Back to Excitement&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/nombrekeff" class="crayons-avatar  crayons-avatar--l  "&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%2Fuser%2Fprofile_image%2F187971%2Fa5359a24-b652-46be-8898-2c5df32aa6e0.png" alt="nombrekeff profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/nombrekeff" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Keff
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Keff
                
              
              &lt;div id="story-author-preview-content-2589909" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/nombrekeff" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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%2Fuser%2Fprofile_image%2F187971%2Fa5359a24-b652-46be-8898-2c5df32aa6e0.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Keff&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/nombrekeff/rediscovering-my-passion-from-burnout-back-to-excitement-cp5" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Jun 27 '25&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/nombrekeff/rediscovering-my-passion-from-burnout-back-to-excitement-cp5" id="article-link-2589909"&gt;
          Rediscovering My Passion: From Burnout Back to Excitement
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/devjournal"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;devjournal&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/developer"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;developer&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/career"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;career&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/leadership"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;leadership&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/nombrekeff/rediscovering-my-passion-from-burnout-back-to-excitement-cp5" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/raised-hands-74b2099fd66a39f2d7eed9305ee0f4553df0eb7b4f11b01b6b1b499973048fe5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;53&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/nombrekeff/rediscovering-my-passion-from-burnout-back-to-excitement-cp5#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              28&lt;span class="hidden s:inline"&gt; comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            2 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>devjournal</category>
      <category>developer</category>
      <category>career</category>
      <category>leadership</category>
    </item>
    <item>
      <title>Rediscovering My Passion: From Burnout Back to Excitement</title>
      <dc:creator>Keff</dc:creator>
      <pubDate>Fri, 27 Jun 2025 13:18:03 +0000</pubDate>
      <link>https://dev.to/nombrekeff/rediscovering-my-passion-from-burnout-back-to-excitement-cp5</link>
      <guid>https://dev.to/nombrekeff/rediscovering-my-passion-from-burnout-back-to-excitement-cp5</guid>
      <description>&lt;p&gt;&lt;strong&gt;Rediscovering My Passion: From Burnout Back to Excitement&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I used to lose track of time coding—pulling late-night sessions just because it was fun. My side projects weren’t even for work; they were pure passion. But after eight years in my last job, I started dreading my IDE. What used to feel like play became a drag, and I’d find myself sighing every time I opened a file. Eventually I realized I had to leave. It took me a couple of years to build up the courage, but quitting turned out to be one of the best decisions I’ve ever made.&lt;/p&gt;




&lt;h3&gt;
  
  
  The Burnout Trap
&lt;/h3&gt;

&lt;p&gt;It wasn’t one big meltdown—more like a slow leak. Mornings felt like a weight, and solving bugs stopped being exciting. Instead of tackling deadlines, I felt chained to them. I realized:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Working there drained me.&lt;/li&gt;
&lt;li&gt;Constant context-switching killed my focus.&lt;/li&gt;
&lt;li&gt;It seemed I carried the company, without being valued.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I missed enjoying coding just for the fun.&lt;/p&gt;




&lt;h3&gt;
  
  
  Hitting Pause (Kind Of)
&lt;/h3&gt;

&lt;p&gt;I spent almost two years unemployed by choice. I didn’t code at all. Some days I loved it—rock climbing, nature photography, and new hobbies filled my time. Other days I hated not writing a single line of code. That push-and-pull helped me figure out what I really wanted.&lt;/p&gt;

&lt;h3&gt;
  
  
  Back to Reality
&lt;/h3&gt;

&lt;p&gt;After two years, money became a reality check. I had to decide: go back to coding (&lt;em&gt;safe&lt;/em&gt;) or switch industries (&lt;em&gt;scary&lt;/em&gt;). I started applying and interviewing, but every process felt off—ghosting, weird vibes, nothing clicked. I worried I wasn’t valuable anymore.&lt;/p&gt;




&lt;h3&gt;
  
  
  A Breath of Fresh Air
&lt;/h3&gt;

&lt;p&gt;Then one company reached out, and the process was different from day one:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Clear process—no radio silence.&lt;/li&gt;
&lt;li&gt;Genuine conversations—they listened and answered my questions.&lt;/li&gt;
&lt;li&gt;Human vibe—every interview felt respectful.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The technical challenge went great, and in the final round HR asked, “What do you like about the company, and what made you apply?” I was honest: I hadn’t dug into their values yet, but I loved the project’s challenges and the team energy. HR wasn’t thrilled and almost rejected me. Luckily, the team lead and technical lead pushed back, convinced HR I was the right fit, and I got the offer.&lt;/p&gt;




&lt;h3&gt;
  
  
  Back in the Groove
&lt;/h3&gt;

&lt;p&gt;I started in April, and it’s been amazing. The work is challenging and fun, and my teammates actually care. Now I:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enjoy the job again.&lt;/li&gt;
&lt;li&gt;Feel valued.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And my hobby keyboard is back on my desk, and those coding sessions are back.&lt;/p&gt;




&lt;h3&gt;
  
  
  Takeaway
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Burnout happens&lt;/strong&gt;—it’s a signal to reset.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Culture matters&lt;/strong&gt;—find teams that treat you like a person.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Take the leap&lt;/strong&gt;—quitting was scary, but it led me here.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you’re stuck in a draining role, remember: stepping away can help, and the right opportunity is out there to reignite your passion.&lt;/p&gt;

</description>
      <category>devjournal</category>
      <category>developer</category>
      <category>career</category>
      <category>leadership</category>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>Keff</dc:creator>
      <pubDate>Tue, 10 Jun 2025 15:36:45 +0000</pubDate>
      <link>https://dev.to/nombrekeff/-35p6</link>
      <guid>https://dev.to/nombrekeff/-35p6</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/nombrekeff/cardboardjs-building-a-simpler-more-intuitive-framework-3j8b" class="crayons-story__hidden-navigation-link"&gt;📦 Cardboard.js: Building a Simpler, More Intuitive Framework&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/nombrekeff" class="crayons-avatar  crayons-avatar--l  "&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%2Fuser%2Fprofile_image%2F187971%2Fa5359a24-b652-46be-8898-2c5df32aa6e0.png" alt="nombrekeff profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/nombrekeff" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Keff
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Keff
                
              
              &lt;div id="story-author-preview-content-2582497" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/nombrekeff" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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%2Fuser%2Fprofile_image%2F187971%2Fa5359a24-b652-46be-8898-2c5df32aa6e0.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Keff&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/nombrekeff/cardboardjs-building-a-simpler-more-intuitive-framework-3j8b" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Jun 10 '25&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/nombrekeff/cardboardjs-building-a-simpler-more-intuitive-framework-3j8b" id="article-link-2582497"&gt;
          📦 Cardboard.js: Building a Simpler, More Intuitive Framework
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/development"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;development&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/devjournal"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;devjournal&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webdev&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/nombrekeff/cardboardjs-building-a-simpler-more-intuitive-framework-3j8b" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;7&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/nombrekeff/cardboardjs-building-a-simpler-more-intuitive-framework-3j8b#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              2&lt;span class="hidden s:inline"&gt; comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            3 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>development</category>
      <category>devjournal</category>
      <category>webdev</category>
    </item>
    <item>
      <title>📦 Cardboard.js: Building a Simpler, More Intuitive Framework</title>
      <dc:creator>Keff</dc:creator>
      <pubDate>Tue, 10 Jun 2025 15:36:25 +0000</pubDate>
      <link>https://dev.to/nombrekeff/cardboardjs-building-a-simpler-more-intuitive-framework-3j8b</link>
      <guid>https://dev.to/nombrekeff/cardboardjs-building-a-simpler-more-intuitive-framework-3j8b</guid>
      <description>&lt;p&gt;Hey there! Hope you're having an amazing week! 🚀&lt;/p&gt;

&lt;p&gt;If you're new here, let me introduce you to &lt;a href="https://github.com/nombrekeff/cardboard-js#-carboardjs" rel="noopener noreferrer"&gt;&lt;strong&gt;Cardboard.js&lt;/strong&gt;&lt;/a&gt;—a lightweight, reactive web framework that lets you build dynamic web apps with just JavaScript or TypeScript. No HTML templates, no unnecessary boilerplate—just clean, reactive code.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Curious? Check out the &lt;a href="https://github.com/nombrekeff/cardboard-js#-carboardjs" rel="noopener noreferrer"&gt;repository&lt;/a&gt; to dive right in!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This post is a &lt;strong&gt;devlog&lt;/strong&gt; and &lt;strong&gt;changelog&lt;/strong&gt; about the latest updates to Cardboard.js. It’s all about making the framework more intuitive, developer-friendly, and powerful. Let’s dive into what’s new and why it matters!&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 The Big Picture: &lt;strong&gt;Making Names Make Sense&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;One of the biggest challenges in any framework is &lt;strong&gt;naming things&lt;/strong&gt;. Names should be intuitive, descriptive, and align with industry standards. In this update, I focused on renaming key concepts in Cardboard.js to make them easier to understand and use.&lt;/p&gt;

&lt;p&gt;Here’s what’s changed:&lt;/p&gt;




&lt;h3&gt;
  
  
  🏗️ &lt;strong&gt;Mount Points: A Cleaner Way to Attach Elements&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Previously, Cardboard used the term &lt;code&gt;attach&lt;/code&gt; for managing where elements are added in the DOM. While functional, it wasn’t very intuitive. So, I’ve renamed it to &lt;strong&gt;mount points&lt;/strong&gt;, a term that’s more familiar to developers.&lt;/p&gt;

&lt;h4&gt;
  
  
  What’s New:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;attach&lt;/code&gt; → &lt;code&gt;mountPoint&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;detach&lt;/code&gt; → &lt;code&gt;restoreMountPoint&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;attached&lt;/code&gt; → &lt;code&gt;getMountPoint&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tag.attach&lt;/code&gt; → &lt;code&gt;tag.mount&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  New Utilities:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;resetMountPoints()&lt;/code&gt; → Resets to the first mount point.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;clearMountPoints()&lt;/code&gt; → Clears all mount points.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;withMountPoints(tag, cb)&lt;/code&gt; → Temporarily sets a mount point for scoped operations.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Before and After:
&lt;/h4&gt;

&lt;p&gt;Here’s how the new API makes your code more readable and intuitive:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;attach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;div1&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="nf"&gt;attach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Child of div1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;attach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;div2&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="nf"&gt;attach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Child of div2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;detach&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="nf"&gt;attach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Child of div1 again&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;attached&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;p&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;child of div1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;After:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;mountPoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;div1&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="nf"&gt;mount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Child of div1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;mountPoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;div2&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="nf"&gt;mount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Child of div2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;restoreMountPoint&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="nf"&gt;mount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Child of div1 again&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;getMountPoint&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;p&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;child of div1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  🔄 &lt;strong&gt;Observables: A More Familiar Name&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Previously called &lt;strong&gt;Consumables&lt;/strong&gt;, these reactive objects hold values and notify listeners when the value changes. While the functionality was great, the name wasn’t. So, I’ve renamed them to &lt;strong&gt;Observables&lt;/strong&gt;, a term that’s widely recognised in the developer community.&lt;/p&gt;

&lt;h4&gt;
  
  
  Why This Matters:
&lt;/h4&gt;

&lt;p&gt;Using familiar terminology reduces the learning curve and makes the framework more approachable for new users.&lt;/p&gt;




&lt;h3&gt;
  
  
  🧠 &lt;strong&gt;Computed Observables: Smarter State Management&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Cardboard now supports &lt;strong&gt;computed observables&lt;/strong&gt;, which let you derive new reactive values from existing ones. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createObservable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&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;isAbove18&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;compute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newVal&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;newVal&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Previously, this was called &lt;code&gt;intersect&lt;/code&gt;, but I’ve renamed it to &lt;strong&gt;compute&lt;/strong&gt; to align with industry standards.&lt;/p&gt;




&lt;h3&gt;
  
  
  ✨ &lt;strong&gt;Built-in Compute Helpers: Now Even Better&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Cardboard offers a set of pre-built compute helpers like &lt;code&gt;greaterThan&lt;/code&gt; and &lt;code&gt;isEmpty&lt;/code&gt;. These were standalone functions, but now they’re available as methods directly on Observables for cleaner, more readable code.&lt;/p&gt;

&lt;h4&gt;
  
  
  Before:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isAbove18&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;greaterThan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;age&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  After:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isAbove18&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;age&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;greaterThan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  🔄 &lt;strong&gt;Lifecycle Events: Standardized Names&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Lifecycle events have been renamed to align with common conventions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;start&lt;/code&gt; → &lt;code&gt;mounted&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;removed&lt;/code&gt; → &lt;code&gt;unmounted&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;beforeRemove&lt;/code&gt; → &lt;code&gt;beforeUnmounted&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🎯 Why These Changes Matter
&lt;/h2&gt;

&lt;p&gt;At first glance, these changes might seem small. But they make a &lt;strong&gt;huge difference&lt;/strong&gt; in how intuitive and enjoyable Cardboard.js is to use. By adopting familiar terminology and simplifying APIs, I’m making it easier for developers to pick up the framework and start building amazing things.&lt;/p&gt;




&lt;h2&gt;
  
  
  🌟 What’s Next?
&lt;/h2&gt;

&lt;p&gt;I’m aiming to release the &lt;strong&gt;first stable version of Cardboard.js&lt;/strong&gt; before the end of the year! There’s still a lot to do, but I’m excited about the progress so far.&lt;/p&gt;

&lt;p&gt;If you’re interested in contributing or just want to follow along, check out the &lt;a href="https://github.com/nombrekeff/cardboard-js" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;. Every star, issue, or pull request helps!&lt;/p&gt;




&lt;h2&gt;
  
  
  ❤️ Join the Community
&lt;/h2&gt;

&lt;p&gt;If you find Cardboard.js interesting, I’d love your feedback! Whether it’s trying out the framework, reporting bugs, or suggesting features, your input is invaluable.&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://github.com/nombrekeff/cardboard-js" rel="noopener noreferrer"&gt;Visit the GitHub Repository&lt;/a&gt;&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Let’s build something amazing together!&lt;/p&gt;

</description>
      <category>development</category>
      <category>devjournal</category>
      <category>webdev</category>
    </item>
    <item>
      <title>📦 Cardboard devlog, what I've done in the last update</title>
      <dc:creator>Keff</dc:creator>
      <pubDate>Mon, 17 Mar 2025 10:05:27 +0000</pubDate>
      <link>https://dev.to/nombrekeff/cardboard-devlog-what-ive-done-in-the-last-update-1n60</link>
      <guid>https://dev.to/nombrekeff/cardboard-devlog-what-ive-done-in-the-last-update-1n60</guid>
      <description>&lt;p&gt;Hey there! Hope you're having a great week!&lt;/p&gt;

&lt;p&gt;I'm building &lt;a href="https://github.com/nombrekeff/cardboard-js#-carboardjs" rel="noopener noreferrer"&gt;Cardboard&lt;/a&gt;, a straightforward, yet powerful reactive web framework. You can look at the &lt;a href="https://github.com/nombrekeff/cardboard-js#-carboardjs" rel="noopener noreferrer"&gt;repo&lt;/a&gt;, or the other articles in the series if you don't know what &lt;strong&gt;Cardboard&lt;/strong&gt; is about!&lt;/p&gt;

&lt;h5&gt;
  
  
  This post is a devlog/changelog about what's happened with Cardboard in the last update. What's been added, changed, and improved.
&lt;/h5&gt;




&lt;h2&gt;
  
  
  Changes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  State
&lt;/h3&gt;

&lt;p&gt;I've re-written the state to use &lt;code&gt;Consumables&lt;/code&gt;. I decided to do this as the previous implementation of the state was unstable, hacky and not very intuitive to be honest.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Consumables&lt;/code&gt; are custom objects that hold a value, can be listened for changes, and can dispatch new values. &lt;/p&gt;

&lt;p&gt;Another inconvenience was that you could only create object/array states, not primitive values. With the new implementation, you can have both.&lt;/p&gt;

&lt;p&gt;By using Consumables the new state is simplified. It's also a lot more stable and intuitive.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;st&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;state&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Now&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;count&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="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;Now we must modify the &lt;code&gt;value&lt;/code&gt; of the consumable.   &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There are many more changes, but not worth mentioning as they're not that interesting :P&lt;/p&gt;


&lt;h2&gt;
  
  
  Additions
&lt;/h2&gt;
&lt;h3&gt;
  
  
  States can now be children
&lt;/h3&gt;

&lt;p&gt;To be able to create reactive text before, you had to use the &lt;code&gt;text&lt;/code&gt; function or &lt;code&gt;tag.text&lt;/code&gt; method. While that did the job, it was a pain if you just wanted to add the Consumable value without interpolating. Let's look at an example to better understand what I mean:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hours&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&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;minutes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nf"&gt;div&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;$hours&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="nx"&gt;hours&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="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;$minutes&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="nx"&gt;minutes&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Now&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hours&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&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;minutes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nf"&gt;div&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hours&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="nx"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Consumable Intersecting
&lt;/h3&gt;

&lt;p&gt;When using Consumables, you might want to check if it has a value, if it's empty, if it's a certain value, etc... &lt;/p&gt;

&lt;p&gt;For this, &lt;strong&gt;Consumables can be intercepted&lt;/strong&gt;, which means that you can create a new Consumable that updates its value based on another Consumable. &lt;/p&gt;

&lt;p&gt;Look at this example:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;temperature&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createConsumable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;32&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;isTooHot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;greaterThanOr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;temperature&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nf"&gt;div&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;showIf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isTooHot&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;As you can see this can be very powerful. &lt;code&gt;isTooHot&lt;/code&gt; will be true if the temperature is higher or equal to 30, and false if less.&lt;br&gt;&lt;br&gt;
The &lt;code&gt;div&lt;/code&gt; will be shown or hidden based on the value of &lt;code&gt;isTooHot&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's look at another example:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;TodoItem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;IConsumable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;TodoItem&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isComplete&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;grab&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;complete&lt;/span&gt;&lt;span class="dl"&gt;'&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;todoText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;grab&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text&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;Empty Todo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;div&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;input&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;setAttrs&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;checkbox&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;changed&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nb"&gt;self&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="nx"&gt;todo&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="nx"&gt;complete&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;self&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="p"&gt;}),&lt;/span&gt;
    &lt;span class="nf"&gt;h4&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todoText&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stylesIf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isComplete&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;textDecoration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;line-through&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;grab&lt;/code&gt; will set its value to a specified value from the original consumable. Whenever &lt;code&gt;todo&lt;/code&gt; changes, the values of &lt;code&gt;isComplete&lt;/code&gt; and &lt;code&gt;todoText&lt;/code&gt; will also update.&lt;br&gt;&lt;br&gt;
If the input checkbox is changed, it will set the complete property. When this happens the &lt;code&gt;h4&lt;/code&gt; will react and set the styles accordingly.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;I'm interested in knowing what you think about this. Do you think the approach I've taken is good? Or would you suggest going another route?&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;code&gt;each&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;The biggest change has been the addition of the &lt;code&gt;each&lt;/code&gt; function. This has taken most of my time and has made me rethink how some aspects of the project work. Most other changes have been made to make &lt;code&gt;each&lt;/code&gt; work properly.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;each&lt;/code&gt; renders lists that update whenever the state changes. The interesting and hard thing is that it's smart and will only update the things that need to be updated. If a value is added, only that value is added to the dom. If a value changes places, only that operation is done.&lt;/p&gt;

&lt;p&gt;This was a bit of a challenge, not only creating the actions to be performed but also handling memory. &lt;/p&gt;

&lt;p&gt;This is how it works:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;colors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;state&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;red&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;orange&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;yellow&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;green&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;blue&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;indigo&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;violet&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;selectedColor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;red&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nf"&gt;div&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;each&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;colors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; 
        &lt;span class="nf"&gt;button&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addStyle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;color&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stylesIf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;equalTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;selectedColor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;fontWeight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bold&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;If a colour is added, removed, or changed places, &lt;code&gt;each&lt;/code&gt; will react and update the list accordingly.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;If you want me to write a more detailed and technical article about how &lt;code&gt;each&lt;/code&gt; works, let me know in the comments and I will get to it. It's pretty interesting!&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h3&gt;
  
  
  Improvements
&lt;/h3&gt;

&lt;p&gt;After working on all of the changes mentioned above, and adding more tests a lot of bugs have been squashed, naming has improved, and the overall stability of the project has increased. &lt;/p&gt;

&lt;p&gt;Additionally, I've spent a lot of time improving the wiki and docs, as well as the README. I think having a decent Wiki and documentation is key from the get-go.&lt;/p&gt;
&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;It's been a productive couple of weeks. I don't think I've ever spent this amount of time working on a single project (&lt;em&gt;outside of work&lt;/em&gt;). But I like how Cardboard is turning out! I think that with a bit more work it can be very powerful and competent. &lt;/p&gt;

&lt;p&gt;I'm aiming to have the first stable version finished before the end of the year! &lt;/p&gt;

&lt;p&gt;If you find the project interesting please consider helping out! &lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/nombrekeff" rel="noopener noreferrer"&gt;
        nombrekeff
      &lt;/a&gt; / &lt;a href="https://github.com/nombrekeff/cardboard-js" rel="noopener noreferrer"&gt;
        cardboard-js
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A very simple, yet powerful reactive framework, to create web applications. All of this with, no HTML, CSS, JSX, and no required build.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;📦 Carboard.js&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/nombrekeff/cardboard-js./header-img.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fnombrekeff%2Fcardboard-js.%2Fheader-img.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/nombrekeff/cardboard-js/actions/workflows/test_main.yml" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/nombrekeff/cardboard-js/actions/workflows/test_main.yml/badge.svg?branch=main&amp;amp;event=push" alt="Tests Main"&gt;&lt;/a&gt;
&lt;a href="https://github.com/nombrekeff/cardboard-js/milestone/1" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/79ea3ca21c4d8d4fd8ec697be9097293c5ec4fdef559bd9f848e36af6fe5fcea/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f50726f6a6563745f5374617475732d5749502d6f72616e6765" alt="Project Status"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Welcome to Cardboard. An &lt;strong&gt;extremely light&lt;/strong&gt; (&lt;em&gt;around &lt;strong&gt;18kb&lt;/strong&gt;&lt;/em&gt;), &lt;strong&gt;performant&lt;/strong&gt;, and &lt;strong&gt;very simple&lt;/strong&gt; reactive framework. It offers almost everything you'd expect from a complete framework. Like managing state, components, logic, and the rest. But with a twist, &lt;strong&gt;you don't need to write any HTML, CSS, or JSX&lt;/strong&gt; if you don't want to. See &lt;strong&gt;&lt;a href="https://github.com/nombrekeff/cardboard-js#what-does-it-do" rel="noopener noreferrer"&gt;what it can do&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;It's similar in philosophy to &lt;a href="https://vanjs.org/" rel="nofollow noopener noreferrer"&gt;VanJS&lt;/a&gt;, if that rings a bell, but with many more features, and a more extensive API.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;!NOTE!&lt;/strong&gt;: Cardboard is in development, use it with caution.&lt;br&gt;
You can check the &lt;a href="https://github.com/nombrekeff/cardboard-js/milestone/1" rel="noopener noreferrer"&gt;v1.0.0 milestone&lt;/a&gt; for a view on the development state - &lt;strong&gt;help is much appreciated!&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight highlight-source-ts notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-v"&gt;Counter&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt; &lt;span class="pl-c1"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
  &lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-s1"&gt;count&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-en"&gt;state&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-c1"&gt;0&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
  &lt;span class="pl-k"&gt;return&lt;/span&gt; &lt;span class="pl-en"&gt;button&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;
    &lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;text&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;`Clicked $count times`&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt; count &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;
    &lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;addStyle&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;'color'&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-s"&gt;'gray'&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;
    &lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;/pre&gt;…
&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/nombrekeff/cardboard-js" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


</description>
      <category>devjournal</category>
      <category>webdev</category>
      <category>programming</category>
      <category>watercooler</category>
    </item>
    <item>
      <title>Is tech boring lately or is it me?? 😐</title>
      <dc:creator>Keff</dc:creator>
      <pubDate>Mon, 18 Dec 2023 13:19:39 +0000</pubDate>
      <link>https://dev.to/nombrekeff/is-tech-boring-lately-or-is-it-me-336</link>
      <guid>https://dev.to/nombrekeff/is-tech-boring-lately-or-is-it-me-336</guid>
      <description>&lt;p&gt;I'm finding tech very boring lately. Nothing seems that exciting or innovative. Just the same stuff with different flavours or efficiency levels.&lt;/p&gt;

&lt;p&gt;So, is this a me thing or do you feel the same way?&lt;/p&gt;

&lt;p&gt;And if you don't, what excites you?&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>watercooler</category>
    </item>
    <item>
      <title>Should listicles be forced to have a tag so we can hide them from feed?</title>
      <dc:creator>Keff</dc:creator>
      <pubDate>Sat, 09 Dec 2023 13:12:36 +0000</pubDate>
      <link>https://dev.to/nombrekeff/should-listicles-be-forced-to-have-a-tag-so-we-can-hide-them-from-feed-1j25</link>
      <guid>https://dev.to/nombrekeff/should-listicles-be-forced-to-have-a-tag-so-we-can-hide-them-from-feed-1j25</guid>
      <description>&lt;p&gt;I know, I know, many people have talked about, and hated on listicles here on DEV many times. &lt;/p&gt;

&lt;p&gt;But to be completely honest, they're some of the most annoying and un-creative articles you can come across. Most of them are useless or offer very little value apart from a collection of X or Y things, or are just cheap marketing. And you can't escape them it seems... They're also bad for beginners, making them feel like they MUST read them in order to progress as developers. And that's not good. &lt;/p&gt;

&lt;p&gt;Listicles are one of the reasons I left DEV for half a year or so. And after coming back it seems it's even worse than before. Maybe the rise of AI is making it even easier to create them.&lt;/p&gt;

&lt;p&gt;I really like this platform. I've been an active member of DEV for many years, have posted numerous articles and have consumed many more. I've read some of the best articles here, and engaged in some of the most interesting discussions and conversations.&lt;/p&gt;

&lt;p&gt;And i know I'm not the only one that dislikes listicles, or even stopped using DEV because of them. This makes me sad, because great articles get lost between all the listicles. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But I think it could be fixed quite simply.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I want to bring up a possible solution to the table, which might've been already suggested, but in case it hasn't, here it is.&lt;/p&gt;

&lt;p&gt;The idea is not to prevent creating listicles, but a way for people who dislike them to hide them from their feed. People who want to see them, can. People who want to create them, can. And people who don't want to see them, can.&lt;/p&gt;

&lt;p&gt;The idea is to "force" listicles to have a tag &lt;code&gt;listicle&lt;/code&gt; or something like that. So that we can hide it from the feed like we hide any other tag.&lt;/p&gt;

&lt;p&gt;Forcing it could be done by the guidelines and mods I guess... &lt;/p&gt;

&lt;p&gt;Or maybe it can be algorithmically done in code or using AI 🤷&lt;/p&gt;

&lt;p&gt;Just a little idea! &lt;/p&gt;

</description>
      <category>meta</category>
      <category>discuss</category>
    </item>
    <item>
      <title>How could AI influence our evolution? 🧠🤖</title>
      <dc:creator>Keff</dc:creator>
      <pubDate>Tue, 21 Nov 2023 21:32:08 +0000</pubDate>
      <link>https://dev.to/nombrekeff/how-could-ai-influence-our-evolution-2cpp</link>
      <guid>https://dev.to/nombrekeff/how-could-ai-influence-our-evolution-2cpp</guid>
      <description>&lt;p&gt;I've always been fascinated by evolution, human evolution in particular. But more precisely, how the things we do and the behaviours we have today could affect our evolution. &lt;/p&gt;

&lt;p&gt;In the last few days, I've been thinking about AI (&lt;em&gt;how strange...&lt;/em&gt;). Not only AI but how AI could affect our evolution.&lt;/p&gt;

&lt;p&gt;Seeing as AI is taking over at a rapid pace, and we use it more and more, even for trivial things. We might get to a point where AI can do so many things for us, that we'll stop needing to do them as often, or at all. &lt;/p&gt;

&lt;p&gt;This popped a question in my head. &lt;strong&gt;What are some things AI could do, that would lead to humans losing some part of their behaviours/intelligence/abilities/... as a part of evolution?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;All of this, of course, at a time when AI is truly useful, integrated and can completely remove the need to do certain things. &lt;/p&gt;

&lt;p&gt;Maybe we become dumber, as there's not much need to think as hard anymore, why would you, if you can just ask good old AI!&lt;/p&gt;

&lt;p&gt;Or let's say that we get to a point, where some tyrannical leadership rules the world and forces all newborns to have AI implanted into their brains...&lt;/p&gt;

&lt;p&gt;By having the AI integrated from birth, humans might lose the need for the ability to reason, as AI will do it for them. Or maybe AI is so good at remembering images, sound, texts, etc... that we don't need to learn to do those things, and over time, humans might become incapable of doing them without the implanted chip.&lt;/p&gt;

&lt;p&gt;Possibilities are endless really, so what do you think?&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>ai</category>
      <category>evolution</category>
    </item>
    <item>
      <title>[Challenge]: Nobody's solved this yet, can you?</title>
      <dc:creator>Keff</dc:creator>
      <pubDate>Fri, 17 Nov 2023 17:08:17 +0000</pubDate>
      <link>https://dev.to/nombrekeff/challenge-nobodys-solved-this-yet-can-you-aj5</link>
      <guid>https://dev.to/nombrekeff/challenge-nobodys-solved-this-yet-can-you-aj5</guid>
      <description>&lt;p&gt;Last week I posted a little cryptic challenge. It's been exactly a week and nobody has solved it yet. Maybe you can!!&lt;/p&gt;

&lt;p&gt;If you haven't checked it yet, go give it a try! &lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/nombrekeff" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--onNKpTrv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/practicaldev/image/fetch/s--hX7RfmcL--/c_fill%2Cf_auto%2Cfl_progressive%2Ch_150%2Cq_auto%2Cw_150/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/187971/a5359a24-b652-46be-8898-2c5df32aa6e0.png" alt="nombrekeff"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/nombrekeff/challenge-can-you-solve-this-puzzle-1947" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;[Challenge]: Cryptic riddle, can you solve it? 🧐&lt;/h2&gt;
      &lt;h3&gt;Keff ・ Nov 10&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#watercooler&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#challenge&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#puzzle&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#fun&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;p&gt;If you checked it but couldn't figure it out, I will share a clue in the comments of this post, hopefully that helps a bit :)&lt;/p&gt;

</description>
      <category>cryptography</category>
      <category>challenge</category>
      <category>watercooler</category>
      <category>learning</category>
    </item>
  </channel>
</rss>
