Back to Examples

Portals, Timers, Observers & Validity

Demo of Portals, Timers (auto-close modal), Intersection Observer, and Form Validity.

Try in Playground

Features Used

  • Portal
  • Timer
  • Intersection Observer
  • Form validity
  • Conditional styling

How to Run

npm install @constela/core @constela/runtime
npx constela run advanced-features.json

Source Code

json
{
  "version": "1.0",
  "state": {
    "showModal": {
      "type": "boolean",
      "initial": false
    },
    "sectionVisible": {
      "type": "boolean",
      "initial": false
    },
    "email": {
      "type": "string",
      "initial": ""
    },
    "countdown": {
      "type": "number",
      "initial": 3
    },
    "timerId": {
      "type": "number",
      "initial": 0
    },
    "submitted": {
      "type": "boolean",
      "initial": false
    }
  },
  "actions": [
    {
      "name": "openModal",
      "steps": [
        {
          "do": "set",
          "target": "showModal",
          "value": {
            "expr": "lit",
            "value": true
          }
        },
        {
          "do": "set",
          "target": "countdown",
          "value": {
            "expr": "lit",
            "value": 3
          }
        },
        {
          "do": "interval",
          "ms": {
            "expr": "lit",
            "value": 1000
          },
          "action": "tickCountdown",
          "result": "timerId"
        }
      ]
    },
    {
      "name": "tickCountdown",
      "steps": [
        {
          "do": "update",
          "target": "countdown",
          "operation": "decrement"
        },
        {
          "do": "if",
          "condition": {
            "expr": "bin",
            "op": "<=",
            "left": {
              "expr": "state",
              "name": "countdown"
            },
            "right": {
              "expr": "lit",
              "value": 0
            }
          },
          "then": [
            {
              "do": "set",
              "target": "showModal",
              "value": {
                "expr": "lit",
                "value": false
              }
            },
            {
              "do": "clearTimer",
              "target": {
                "expr": "state",
                "name": "timerId"
              }
            }
          ]
        }
      ]
    },
    {
      "name": "closeModal",
      "steps": [
        {
          "do": "clearTimer",
          "target": {
            "expr": "state",
            "name": "timerId"
          }
        },
        {
          "do": "set",
          "target": "showModal",
          "value": {
            "expr": "lit",
            "value": false
          }
        }
      ]
    },
    {
      "name": "onSectionVisible",
      "steps": [
        {
          "do": "set",
          "target": "sectionVisible",
          "value": {
            "expr": "lit",
            "value": true
          }
        }
      ]
    },
    {
      "name": "setEmail",
      "steps": [
        {
          "do": "set",
          "target": "email",
          "value": {
            "expr": "var",
            "name": "value"
          }
        }
      ]
    },
    {
      "name": "submit",
      "steps": [
        {
          "do": "set",
          "target": "submitted",
          "value": {
            "expr": "lit",
            "value": true
          }
        },
        {
          "do": "delay",
          "ms": {
            "expr": "lit",
            "value": 3000
          },
          "then": [
            {
              "do": "set",
              "target": "submitted",
              "value": {
                "expr": "lit",
                "value": false
              }
            }
          ]
        }
      ]
    }
  ],
  "view": {
    "kind": "element",
    "tag": "div",
    "props": {
      "style": {
        "expr": "lit",
        "value": "font-family: system-ui, sans-serif; padding: 16px;"
      }
    },
    "children": [
      {
        "kind": "element",
        "tag": "h1",
        "props": {
          "style": {
            "expr": "lit",
            "value": "margin: 0 0 8px 0; font-size: 24px;"
          }
        },
        "children": [
          {
            "kind": "text",
            "value": {
              "expr": "lit",
              "value": "Portals, Timers, Observers & Validity"
            }
          }
        ]
      },
      {
        "kind": "element",
        "tag": "p",
        "props": {
          "style": {
            "expr": "lit",
            "value": "color: #666; margin: 0 0 24px 0;"
          }
        },
        "children": [
          {
            "kind": "text",
            "value": {
              "expr": "lit",
              "value": "Demonstrating Portals, Observers, and Form Validity."
            }
          }
        ]
      },
      {
        "kind": "element",
        "tag": "div",
        "props": {
          "style": {
            "expr": "lit",
            "value": "margin-bottom: 24px; padding: 16px; background: #f5f5f5; border-radius: 8px;"
          }
        },
        "children": [
          {
            "kind": "element",
            "tag": "h2",
            "props": {
              "style": {
                "expr": "lit",
                "value": "font-size: 18px; margin: 0 0 12px 0; color: #333;"
              }
            },
            "children": [
              {
                "kind": "text",
                "value": {
                  "expr": "lit",
                  "value": "1. Portals & Timers"
                }
              }
            ]
          },
          {
            "kind": "element",
            "tag": "p",
            "props": {
              "style": {
                "expr": "lit",
                "value": "color: #666; margin: 0 0 12px 0; font-size: 14px;"
              }
            },
            "children": [
              {
                "kind": "text",
                "value": {
                  "expr": "lit",
                  "value": "Render content outside the component tree. Modal auto-closes in 3 seconds."
                }
              }
            ]
          },
          {
            "kind": "element",
            "tag": "button",
            "props": {
              "style": {
                "expr": "lit",
                "value": "padding: 8px 16px; background: #0070f3; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 14px;"
              },
              "onClick": {
                "event": "click",
                "action": "openModal"
              }
            },
            "children": [
              {
                "kind": "text",
                "value": {
                  "expr": "lit",
                  "value": "Open Modal"
                }
              }
            ]
          }
        ]
      },
      {
        "kind": "element",
        "tag": "div",
        "props": {
          "style": {
            "expr": "cond",
            "if": {
              "expr": "state",
              "name": "sectionVisible"
            },
            "then": {
              "expr": "lit",
              "value": "margin-bottom: 24px; padding: 16px; background: #e0f2fe; border-radius: 8px; transition: all 0.5s; transform: translateY(0); opacity: 1;"
            },
            "else": {
              "expr": "lit",
              "value": "margin-bottom: 24px; padding: 16px; background: #f5f5f5; border-radius: 8px; transition: all 0.5s; transform: translateY(20px); opacity: 0.5;"
            }
          },
          "onIntersect": {
            "event": "intersect",
            "action": "onSectionVisible"
          }
        },
        "children": [
          {
            "kind": "element",
            "tag": "h2",
            "props": {
              "style": {
                "expr": "lit",
                "value": "font-size: 18px; margin: 0 0 12px 0; color: #333;"
              }
            },
            "children": [
              {
                "kind": "text",
                "value": {
                  "expr": "lit",
                  "value": "2. Observers"
                }
              }
            ]
          },
          {
            "kind": "element",
            "tag": "p",
            "props": {
              "style": {
                "expr": "lit",
                "value": "color: #666; margin: 0; font-size: 14px;"
              }
            },
            "children": [
              {
                "kind": "text",
                "value": {
                  "expr": "lit",
                  "value": "This section uses Intersection Observer. Status: "
                }
              },
              {
                "kind": "element",
                "tag": "span",
                "props": {
                  "style": {
                    "expr": "cond",
                    "if": {
                      "expr": "state",
                      "name": "sectionVisible"
                    },
                    "then": {
                      "expr": "lit",
                      "value": "font-weight: bold; color: #16a34a;"
                    },
                    "else": {
                      "expr": "lit",
                      "value": "font-weight: bold; color: #666;"
                    }
                  }
                },
                "children": [
                  {
                    "kind": "text",
                    "value": {
                      "expr": "cond",
                      "if": {
                        "expr": "state",
                        "name": "sectionVisible"
                      },
                      "then": {
                        "expr": "lit",
                        "value": "Visible"
                      },
                      "else": {
                        "expr": "lit",
                        "value": "Not visible"
                      }
                    }
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        "kind": "element",
        "tag": "div",
        "props": {
          "style": {
            "expr": "lit",
            "value": "margin-bottom: 24px; padding: 16px; background: #f5f5f5; border-radius: 8px;"
          }
        },
        "children": [
          {
            "kind": "element",
            "tag": "h2",
            "props": {
              "style": {
                "expr": "lit",
                "value": "font-size: 18px; margin: 0 0 12px 0; color: #333;"
              }
            },
            "children": [
              {
                "kind": "text",
                "value": {
                  "expr": "lit",
                  "value": "3. Form Validity"
                }
              }
            ]
          },
          {
            "kind": "element",
            "tag": "p",
            "props": {
              "style": {
                "expr": "lit",
                "value": "color: #666; margin: 0 0 12px 0; font-size: 14px;"
              }
            },
            "children": [
              {
                "kind": "text",
                "value": {
                  "expr": "lit",
                  "value": "Real-time form validation using validity expressions."
                }
              }
            ]
          },
          {
            "kind": "element",
            "tag": "div",
            "props": {
              "style": {
                "expr": "lit",
                "value": "display: flex; flex-direction: column; gap: 8px;"
              }
            },
            "children": [
              {
                "kind": "element",
                "tag": "input",
                "ref": "emailInput",
                "props": {
                  "type": {
                    "expr": "lit",
                    "value": "email"
                  },
                  "placeholder": {
                    "expr": "lit",
                    "value": "Enter your email"
                  },
                  "style": {
                    "expr": "lit",
                    "value": "padding: 8px 12px; border: 1px solid #ccc; border-radius: 4px; font-size: 14px; color: #333;"
                  },
                  "value": {
                    "expr": "state",
                    "name": "email"
                  },
                  "onInput": {
                    "event": "input",
                    "action": "setEmail",
                    "payload": {
                      "expr": "var",
                      "name": "value"
                    }
                  }
                }
              },
              {
                "kind": "if",
                "condition": {
                  "expr": "bin",
                  "op": "&&",
                  "left": {
                    "expr": "state",
                    "name": "email"
                  },
                  "right": {
                    "expr": "not",
                    "operand": {
                      "expr": "validity",
                      "ref": "emailInput",
                      "property": "valid"
                    }
                  }
                },
                "then": {
                  "kind": "element",
                  "tag": "p",
                  "props": {
                    "style": {
                      "expr": "lit",
                      "value": "color: #dc2626; font-size: 12px; margin: 0;"
                    }
                  },
                  "children": [
                    {
                      "kind": "text",
                      "value": {
                        "expr": "lit",
                        "value": "Please enter a valid email address"
                      }
                    }
                  ]
                }
              },
              {
                "kind": "element",
                "tag": "button",
                "props": {
                  "style": {
                    "expr": "cond",
                    "if": {
                      "expr": "validity",
                      "ref": "emailInput",
                      "property": "valid"
                    },
                    "then": {
                      "expr": "lit",
                      "value": "padding: 8px 16px; background: #0070f3; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 14px;"
                    },
                    "else": {
                      "expr": "lit",
                      "value": "padding: 8px 16px; background: #ccc; color: #666; border: none; border-radius: 4px; cursor: not-allowed; font-size: 14px;"
                    }
                  },
                  "disabled": {
                    "expr": "not",
                    "operand": {
                      "expr": "validity",
                      "ref": "emailInput",
                      "property": "valid"
                    }
                  },
                  "onClick": {
                    "event": "click",
                    "action": "submit"
                  }
                },
                "children": [
                  {
                    "kind": "text",
                    "value": {
                      "expr": "lit",
                      "value": "Submit"
                    }
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        "kind": "if",
        "condition": {
          "expr": "state",
          "name": "showModal"
        },
        "then": {
          "kind": "portal",
          "target": "body",
          "children": [
            {
              "kind": "element",
              "tag": "div",
              "props": {
                "style": {
                  "expr": "lit",
                  "value": "position: fixed; inset: 0; background: rgba(0,0,0,0.5); display: flex; align-items: center; justify-content: center; z-index: 1000;"
                }
              },
              "children": [
                {
                  "kind": "element",
                  "tag": "div",
                  "props": {
                    "style": {
                      "expr": "lit",
                      "value": "background: white; padding: 24px; border-radius: 8px; max-width: 400px; width: 90%;"
                    }
                  },
                  "children": [
                    {
                      "kind": "element",
                      "tag": "h3",
                      "props": {
                        "style": {
                          "expr": "lit",
                          "value": "margin: 0 0 16px 0; font-size: 18px; color: #333;"
                        }
                      },
                      "children": [
                        {
                          "kind": "text",
                          "value": {
                            "expr": "lit",
                            "value": "Portal Modal"
                          }
                        }
                      ]
                    },
                    {
                      "kind": "element",
                      "tag": "p",
                      "props": {
                        "style": {
                          "expr": "lit",
                          "value": "color: #666; margin: 0 0 16px 0;"
                        }
                      },
                      "children": [
                        {
                          "kind": "text",
                          "value": {
                            "expr": "lit",
                            "value": "This modal is rendered via a Portal. Auto-closes in "
                          }
                        },
                        {
                          "kind": "text",
                          "value": {
                            "expr": "state",
                            "name": "countdown"
                          }
                        },
                        {
                          "kind": "text",
                          "value": {
                            "expr": "lit",
                            "value": " seconds."
                          }
                        }
                      ]
                    },
                    {
                      "kind": "element",
                      "tag": "button",
                      "props": {
                        "style": {
                          "expr": "lit",
                          "value": "padding: 8px 16px; background: #0070f3; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 14px;"
                        },
                        "onClick": {
                          "event": "click",
                          "action": "closeModal"
                        }
                      },
                      "children": [
                        {
                          "kind": "text",
                          "value": {
                            "expr": "lit",
                            "value": "Close"
                          }
                        }
                      ]
                    }
                  ]
                }
              ]
            }
          ]
        }
      },
      {
        "kind": "if",
        "condition": {
          "expr": "state",
          "name": "submitted"
        },
        "then": {
          "kind": "element",
          "tag": "div",
          "props": {
            "style": {
              "expr": "lit",
              "value": "position: fixed; bottom: 24px; right: 24px; background: #16a34a; color: white; padding: 16px 24px; border-radius: 8px; box-shadow: 0 4px 12px rgba(0,0,0,0.15); font-size: 14px; z-index: 1000;"
            }
          },
          "children": [
            {
              "kind": "text",
              "value": {
                "expr": "lit",
                "value": "Form submitted successfully!"
              }
            }
          ]
        }
      }
    ]
  }
}