diff --git a/README.md b/README.md
index 4055a2a..b036ba3 100644
--- a/README.md
+++ b/README.md
@@ -1,16 +1,20 @@
 # HSX
 
-HSX (Hypertext S-expression) is a simple yet powerful HTML5 generation library for Common Lisp. It was forked from [flute](https://github.com/ailisp/flute/).
+HSX (Hypertext S-expression) is a simple and powerful HTML (Living Standard) generation library for Common Lisp.
 
-## Introduction
+This project is a fork of [ailisp/flute](https://github.com/ailisp/flute/).
 
-HSX allows you to generate HTML using S-expressions, providing a more Lisp-friendly way to create web content. By using the `hsx` macro, you can define HTML elements and their attributes in a concise and readable manner.
+## Warning
+
+This software is still in ALPHA quality. The APIs are likely to change.
+
+Please check the [release notes](https://github.com/skyizwhite/hsx/releases) for updates.
 
 ## Getting Started
 
 ### Basic Usage
 
-Use the `hsx` macro to create HTML elements. Attributes are specified using a property list following the element name, and child elements are nested directly within.
+Use the `hsx` macro to create HTML elements. Attributes are specified using a property list after the element name, and child elements are nested directly inside.
 
 ```lisp
 (hsx
@@ -28,21 +32,30 @@ This generates:
 </div>
 ```
 
-## Examples
+To convert an HSX object into an HTML string, use the `render-to-string` function:
 
-### Dynamic Content
+```lisp
+(render-to-string
+  (hsx ...))
+```
 
-HSX allows embedding Common Lisp code directly within your HTML structure, making it easy to generate dynamic content.
+### Embedding Content
+
+HSX allows you to embed Common Lisp forms directly within your HTML structure.
+
+When working with HSX elements inside embedded Lisp forms, you should use the `hsx` macro again.
 
 ```lisp
 (hsx
   (div
     (p :id (format nil "id-~a" (random 100)))
     (ul
-      (loop :for i :from 1 :to 5 :collect (li (format nil "Item ~a" i))))
+      (loop
+        :for i :from 1 :to 5 :collect
+        (hsx (li (format nil "Item ~a" i)))))
     (if (> (random 10) 5)
-        (p "Condition met!")
-        (p "Condition not met!"))))
+        (hsx (p "Condition met!"))
+        (hsx (p "Condition not met!")))))
 ```
 
 This might generate:
@@ -81,22 +94,22 @@ This generates:
 <p>Second paragraph.</p>
 ```
 
-## Creating Components
+### Creating Components
 
-You can define reusable components with the `defcomp` macro. Components are functions that can take keyword arguments and properties.
+You can define reusable components using the `defcomp` macro. Component names must begin with a tilde (`~`). Properties should be declared using `&key`, `&rest`, or both. The body must return an HSX element.
 
 ```lisp
-(defcomp card (&key title children)
+(defcomp ~card (&key title children)
   (hsx
     (div :class "card"
       (h1 title)
       children)))
 ```
 
-Or using a property list:
+Alternatively, you can use a property list:
 
 ```lisp
-(defcomp card (&rest props)
+(defcomp ~card (&rest props)
   (hsx
     (div :class "card"
       (h1 (getf props :title))
@@ -107,7 +120,7 @@ Usage example:
 
 ```lisp
 (hsx
-  (card :title "Card Title"
+  (~card :title "Card Title"
     (p "This is a card component.")))
 ```
 
@@ -120,18 +133,6 @@ Generates:
 </div>
 ```
 
-## Rendering HTML
-
-To render HSX to an HTML string, use the `render-to-string` function.
-
-```lisp
-(render-to-string
-  (hsx
-    (div :class "content"
-      (h1 "Rendered to String")
-      (p "This HTML is generated as a string."))))
-```
-
 ## License
 
 This project is licensed under the MIT License.
diff --git a/hsx.asd b/hsx.asd
index aba1850..c5ab13d 100644
--- a/hsx.asd
+++ b/hsx.asd
@@ -1,6 +1,6 @@
 (defsystem "hsx"
-  :version "0.1.0"
-  :description "Hypertext S-expression"
+  :version "0.4.0"
+  :description "Simple and powerful HTML generation library."
   :author "skyizwhite, Bo Yao"
   :maintainer "skyizwhite <paku@skyizwhite.dev>"
   :license "MIT"
diff --git a/src/dsl.lisp b/src/dsl.lisp
index 680c85a..27d785a 100644
--- a/src/dsl.lisp
+++ b/src/dsl.lisp
@@ -13,21 +13,37 @@
 ;;;; hsx macro
 
 (defmacro hsx (form)
-  "Detect built-in HSX elements and automatically import them."
-  (find-builtin-symbols form))
+  "Detect HSX elements and automatically import them."
+  (detect-elements form))
 
-(defun find-builtin-symbols (node)
-  (if (atom node)
-      (or (and (symbolp node)
-               (not (keywordp node))
-               (find-symbol (string node) :hsx/builtin))
-          node)
-      (cons (find-builtin-symbols (car node))
-            (mapcar (lambda (n)
-                      (if (listp n)
-                          (find-builtin-symbols n)
-                          n))
-                    (cdr node)))))
+(defun detect-builtin-symbol (sym)
+  (multiple-value-bind (builtin-sym kind)
+      (find-symbol (string sym) :hsx/builtin)
+    (and (eq kind :external) builtin-sym)))
+
+(defun start-with-tilde-p (sym)
+  (string= "~" (subseq (string sym) 0 1)))
+
+(defun detect-component-symbol (sym)
+  (and (start-with-tilde-p sym) sym))
+
+(defun detect-elements (form)
+  (check-type form cons)
+  (let* ((head (first form))
+         (tail (rest form))
+         (well-formed-p (listp tail))
+         (detected-sym (and (symbolp head)
+                            (not (keywordp head))
+                            (or (detect-builtin-symbol head)
+                                (detect-component-symbol head)))))
+    (if (and well-formed-p detected-sym)
+        (cons detected-sym
+              (mapcar (lambda (sub-form)
+                        (if (consp sub-form)
+                            (detect-elements sub-form)
+                            sub-form))
+                      tail))
+        form)))
 
 ;;;; defhsx macro
 
@@ -58,16 +74,19 @@
   `(eval-when (:compile-toplevel :load-toplevel :execute)
      (defhsx ,name ,(make-keyword name))))
 
-(defmacro defcomp (name props &body body)
-  "Define a function component for use in HSX.
-The props must be declared with either &key or &rest (or both).
-The body must return an HSX element."
+(defmacro defcomp (~name props &body body)
+  "Define an HSX function component.
+The component name must start with a tilde (~).
+Component properties must be declared using &key, &rest, or both.
+The body of the component must produce a valid HSX element."
+  (unless (start-with-tilde-p ~name)
+    (error "The component name must start with a tilde (~~)."))
   (unless (or (null props)
               (member '&key props)
               (member '&rest props))
-    (error "Component properties must be declared with either &key, &rest, or both."))
-  (let ((%name (symbolicate '% name)))
+    (error "Component properties must be declared using &key, &rest, or both."))
+  (let ((%name (symbolicate '% ~name)))
     `(eval-when (:compile-toplevel :load-toplevel :execute)
        (defun ,%name ,props
          ,@body)
-       (defhsx ,name (fdefinition ',%name)))))
+       (defhsx ,~name (fdefinition ',%name)))))
diff --git a/tests/dsl.lisp b/tests/dsl.lisp
index d8bce5d..31abea8 100644
--- a/tests/dsl.lisp
+++ b/tests/dsl.lisp
@@ -1,67 +1,79 @@
 (defpackage #:hsx-test/dsl
   (:use #:cl
         #:rove
-        #:hsx/dsl
-        #:hsx/builtin)
+        #:hsx/dsl)
+  (:import-from #:hsx/builtin)
   (:import-from #:hsx/element
                 #:element-props
                 #:element-children))
 (in-package #:hsx-test/dsl)
 
+(defcomp ~comp1 (&key children)
+  (hsx (div children)))
+
+(deftest detect-elements-test
+  (testing "detect-tags"
+    (ok (expands '(hsx (div div div))
+                 '(hsx/builtin:div div div)))
+    (ok (expands '(hsx (div (div div (div))))
+                 '(hsx/builtin:div
+                   (hsx/builtin:div
+                     div
+                     (hsx/builtin:div))))))
+
+  (testing "detect-components"
+    (ok (expands '(hsx (~comp1 (div)))
+                 '(~comp1 (hsx/builtin:div)))))
+
+  (testing "ignore-malformed-form"
+    (ok (expands '(hsx (div . div))
+                 '(div . div)))
+    (ok (expands '(hsx ((div)))
+                 '((div)))))
+
+  (testing "ignore-cl-form"
+    (ok (expands '(hsx (labels ((div () "div"))
+                         (div)))
+                 '(labels ((div () "div"))
+                   (div))))))
+
 (deftest dsl-test
-  (testing "find-symbols"
-    (ok (expands
-         '(hsx (div '(:div "div")
-                 div
-                 (div
-                   'div
-                   (div)
-                   :div)
-                 "div"))
-         '(hsx/builtin:div '(:div "div")
-           div
-           (hsx/builtin:div
-             'div
-             (hsx/builtin:div)
-             :div)
-           "div"))))
-  
   (testing "empty-hsx"
-    (let ((elm (div)))
+    (let ((elm (hsx (div))))
       (ok (null (element-props elm)))
       (ok (null (element-children elm)))))
  
   (testing "hsx-with-static-props"
-    (let ((elm (div :prop1 "value1" :prop2 "value2")))
+    (let ((elm (hsx (div :prop1 "value1" :prop2 "value2"))))
       (ok (equal '(:prop1 "value1" :prop2 "value2")
                  (element-props elm)))
       (ok (null (element-children elm)))))
   
   (testing "hsx-with-dynamic-props"
     (let* ((props '(:prop1 "value1" :prop2 "value2"))
-           (elm (div props)))
+           (elm (hsx (div props))))
       (ok (equal props (element-props elm)))
       (ok (null (element-children elm)))))
   
   (testing "hsx-with-children"
-    (let ((elm (div
-                 "child1"
-                 "child2")))
+    (let ((elm (hsx (div
+                      "child1"
+                      "child2"))))
       (ok (null (element-props elm)))
       (ok (equal (list "child1" "child2") (element-children elm)))))
   
   (testing "hsx-with-static-props-and-children"
-    (let ((elm (div :prop1 "value1" :prop2 "value2"
-                 "child1"
-                 "child2")))
+    (let ((elm (hsx (div :prop1 "value1" :prop2 "value2"
+                      "child1"
+                      "child2"))))
       (ok (equal '(:prop1 "value1" :prop2 "value2")
                  (element-props elm)))
       (ok (equal (list "child1" "child2") (element-children elm)))))
   
   (testing "hsx-with-dynamic-props-and-children"
     (let* ((props '(:prop1 "value1" :prop2 "value2"))
-           (elm (div props
-                  "child1"
-                  "child2")))
+           (elm (hsx (div props
+                       "child1"
+                       "child2"))))
       (ok (equal props (element-props elm)))
       (ok (equal (list "child1" "child2") (element-children elm))))))