diff --git a/CHANGELOG.md b/CHANGELOG.md
index b35fa95..7d5370a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -18,6 +18,14 @@ and this project attempts to adhere to [Semantic Versioning](https://semver.org/

 ## [Unreleased]

+### Changed
+
+- **Internal**: Improved handling of component parameters in loops by creating fresh `Params` instances for each render. Previously, a single `Params` instance was reused across renders, which could cause issues with attribute resolution in loops. The `BirdNode` now stores raw attributes instead of a `Params` instance, and creates a new `Params` instance for each render.
+
+### Fixed
+
+- Fixed an issue where nested variable resolution (e.g., `item.url`) would fail in loops after the first iteration. This was caused by attributes being consumed during the first render and not being available for subsequent renders.
+
 ## [0.7.1]

 ### Removed
diff --git a/src/django_bird/params.py b/src/django_bird/params.py
index 92688f3..2386e1e 100644
--- a/src/django_bird/params.py
+++ b/src/django_bird/params.py
@@ -10,7 +10,7 @@ from django.template.context import Context
 from django.utils.safestring import SafeString
 from django.utils.safestring import mark_safe

-from ._typing import TagBits
+from .templatetags.tags.prop import PropNode


 @dataclass
@@ -18,7 +18,7 @@ class Value:
     raw: str | bool | None
     quoted: bool = False

-    def resolve(self, context: Context) -> Any:
+    def resolve(self, context: Context | dict[str, Any]) -> Any:
         if self.raw is None or (isinstance(self.raw, str) and self.raw == "False"):
             return None
         if (isinstance(self.raw, bool) and self.raw) or (
@@ -71,9 +71,12 @@ class Params:
     attrs: list[Param] = field(default_factory=list)
     props: list[Param] = field(default_factory=list)

-    def render_props(self, nodelist: NodeList | None, context: Context):
-        from django_bird.templatetags.tags.prop import PropNode
+    @classmethod
+    def with_attrs(cls, attrs: list[Param] | None) -> Params:
+        """Create a Params instance with a copy of the provided attrs."""
+        return cls(attrs=attrs.copy() if attrs is not None else [], props=[])

+    def render_props(self, nodelist: NodeList | None, context: Context):
         if nodelist is None:
             return

@@ -83,13 +86,13 @@ class Params:
             if not isinstance(node, PropNode):
                 continue

-            # Create a Value instance for the default
             value = Value(node.default, quoted=False)

             for idx, attr in enumerate(self.attrs):
                 if node.name == attr.name:
-                    if attr.value.raw is not None:  # Changed from attr.value
-                        value = attr.value  # Now passing the entire Value instance
+                    resolved = attr.value.resolve(context)
+                    if resolved is not None:
+                        value = attr.value
                     attrs_to_remove.add(idx)

             self.props.append(Param(name=node.name, value=value))
@@ -102,11 +105,3 @@ class Params:
     def render_attrs(self, context: Context) -> SafeString:
         rendered = " ".join(attr.render_attr(context) for attr in self.attrs)
         return mark_safe(rendered)
-
-    @classmethod
-    def from_bits(cls, bits: TagBits):
-        params: list[Param] = []
-        for bit in bits:
-            param = Param.from_bit(bit)
-            params.append(param)
-        return cls(attrs=params)
diff --git a/src/django_bird/templatetags/tags/bird.py b/src/django_bird/templatetags/tags/bird.py
index 6fb5b64..54e975e 100644
--- a/src/django_bird/templatetags/tags/bird.py
+++ b/src/django_bird/templatetags/tags/bird.py
@@ -13,6 +13,7 @@ from django_bird._typing import TagBits
 from django_bird._typing import override
 from django_bird.components import Component
 from django_bird.components import components
+from django_bird.params import Param
 from django_bird.params import Params
 from django_bird.slots import DEFAULT_SLOT
 from django_bird.slots import Slots
@@ -24,9 +25,12 @@ END_TAG = "endbird"
 def do_bird(parser: Parser, token: Token) -> BirdNode:
     bits = token.split_contents()
     name = parse_bird_name(bits)
-    params = Params.from_bits(bits[2:])
+    attrs = []
+    for bit in bits[2:]:
+        param = Param.from_bit(bit)
+        attrs.append(param)
     nodelist = parse_nodelist(bits, parser)
-    return BirdNode(name, params, nodelist)
+    return BirdNode(name, attrs, nodelist)


 def parse_bird_name(bits: TagBits) -> str:
@@ -52,9 +56,11 @@ def parse_nodelist(bits: TagBits, parser: Parser) -> NodeList | None:


 class BirdNode(template.Node):
-    def __init__(self, name: str, params: Params, nodelist: NodeList | None) -> None:
+    def __init__(
+        self, name: str, attrs: list[Param], nodelist: NodeList | None
+    ) -> None:
         self.name = name
-        self.params = params
+        self.attrs = attrs
         self.nodelist = nodelist

     @override
@@ -74,8 +80,9 @@ class BirdNode(template.Node):
     def get_component_context_data(
         self, component: Component, context: Context
     ) -> dict[str, Any]:
-        props = self.params.render_props(component.nodelist, context)
-        attrs = self.params.render_attrs(context)
+        params = Params.with_attrs(self.attrs)
+        props = params.render_props(component.nodelist, context)
+        attrs = params.render_attrs(context)
         slots = Slots.collect(self.nodelist, context).render()
         default_slot = slots.get(DEFAULT_SLOT) or context.get("slot")
         return {
diff --git a/tests/templatetags/test_bird.py b/tests/templatetags/test_bird.py
index 0f7c14d..99a12d4 100644
--- a/tests/templatetags/test_bird.py
+++ b/tests/templatetags/test_bird.py
@@ -12,7 +12,6 @@ from django.template.base import TokenType
 from django.template.exceptions import TemplateSyntaxError

 from django_bird.params import Param
-from django_bird.params import Params
 from django_bird.params import Value
 from django_bird.templatetags.tags.bird import END_TAG
 from django_bird.templatetags.tags.bird import TAG
@@ -38,6 +37,45 @@ class TestTemplateTag:
         node = do_bird(parser, token)
         assert node.name == expected

+    @pytest.mark.parametrize(
+        "params,expected_attrs",
+        [
+            (
+                "class='btn'",
+                [Param(name="class", value=Value("btn", quoted=True))],
+            ),
+            (
+                "class='btn' id='my-btn'",
+                [
+                    Param(name="class", value=Value("btn", quoted=True)),
+                    Param(name="id", value=Value("my-btn", quoted=True)),
+                ],
+            ),
+            (
+                "disabled",
+                [Param(name="disabled", value=Value(True))],
+            ),
+            (
+                "class=dynamic",
+                [Param(name="class", value=Value("dynamic", quoted=False))],
+            ),
+            (
+                "class=item.name id=user.id",
+                [
+                    Param(name="class", value=Value("item.name", quoted=False)),
+                    Param(name="id", value=Value("user.id", quoted=False)),
+                ],
+            ),
+        ],
+    )
+    def test_attrs_parsing(self, params, expected_attrs):
+        token = Token(TokenType.BLOCK, f"{TAG} button {params}")
+        parser = Parser(
+            [Token(TokenType.BLOCK, END_TAG)],
+        )
+        node = do_bird(parser, token)
+        assert node.attrs == expected_attrs
+
     def test_missing_argument(self):
         token = Token(TokenType.BLOCK, TAG)
         parser = Parser(
@@ -47,48 +85,43 @@ class TestTemplateTag:
             do_bird(parser, token)

     @pytest.mark.parametrize(
-        "params,expected_params",
+        "params,expected_attrs",
         [
             (
                 "class='btn'",
-                Params(attrs=[Param(name="class", value=Value("btn", quoted=True))]),
+                [Param(name="class", value=Value("btn", quoted=True))],
             ),
             (
                 "class='btn' id='my-btn'",
-                Params(
-                    attrs=[
-                        Param(name="class", value=Value("btn", quoted=True)),
-                        Param(name="id", value=Value("my-btn", quoted=True)),
-                    ]
-                ),
+                [
+                    Param(name="class", value=Value("btn", quoted=True)),
+                    Param(name="id", value=Value("my-btn", quoted=True)),
+                ],
+            ),
+            (
+                "disabled",
+                [Param(name="disabled", value=Value(True))],
             ),
-            ("disabled", Params(attrs=[Param(name="disabled", value=Value(True))])),
             (
                 "class=dynamic_class",
-                Params(
-                    attrs=[
-                        Param(name="class", value=Value("dynamic_class", quoted=False))
-                    ]
-                ),
+                [Param(name="class", value=Value("dynamic_class", quoted=False))],
             ),
             (
                 "class=item.name id=user.id",
-                Params(
-                    attrs=[
-                        Param(name="class", value=Value("item.name", quoted=False)),
-                        Param(name="id", value=Value("user.id", quoted=False)),
-                    ]
-                ),
+                [
+                    Param(name="class", value=Value("item.name", quoted=False)),
+                    Param(name="id", value=Value("user.id", quoted=False)),
+                ],
             ),
         ],
     )
-    def test_node_params(self, params, expected_params):
+    def test_node_attrs(self, params, expected_attrs):
         token = Token(TokenType.BLOCK, f"{TAG} button {params}")
         parser = Parser(
             [Token(TokenType.BLOCK, END_TAG)],
         )
         node = do_bird(parser, token)
-        assert node.params == expected_params
+        assert node.attrs == expected_attrs

     @pytest.mark.parametrize(
         "component,template,context,expected",
@@ -438,6 +471,58 @@ class TestTemplateTag:
         rendered = t.render(context=Context(context))
         assert normalize_whitespace(rendered) == expected

+    def test_nested_variable_resolution(
+        self, create_bird_template, normalize_whitespace
+    ):
+        # Create the nav and nav.item components
+        create_bird_template(
+            "nav",
+            """
+            <nav>
+                {{ slot }}
+            </nav>
+            """,
+        )
+
+        create_bird_template(
+            "nav.item",
+            """
+            {% bird:prop href="#" %}
+            <a href="{{ props.href }}">{{ slot }}</a>
+            """,
+        )
+
+        # Create the template that uses these components
+        template = Template("""
+            {% bird nav %}
+                {% for item in items %}
+                    {% bird nav.item href=item.url %}
+                        {{ item.title }}
+                    {% endbird nav.item %}
+                {% endfor %}
+            {% endbird nav %}
+        """)
+
+        # Create context with nested data
+        context = Context(
+            {
+                "items": [
+                    {"url": "/", "title": "Home"},
+                    {"url": "/admin", "title": "Admin"},
+                ]
+            }
+        )
+
+        expected = normalize_whitespace("""
+            <nav>
+                <a href="/">Home</a>
+                <a href="/admin">Admin</a>
+            </nav>
+        """)
+
+        rendered = normalize_whitespace(template.render(context))
+        assert rendered == expected
+

 @pytest.mark.xfail(reason="Feature not implemented yet")
 class TestTemplateTagFutureFeatures:
@@ -468,7 +553,7 @@ class TestNode:
     )
     def test_get_component_name(self, name, context, expected, create_bird_template):
         create_bird_template(name=name, content="<button>Click me</button>")
-        node = BirdNode(name=name, params=Params([]), nodelist=None)
+        node = BirdNode(name=name, attrs=[], nodelist=None)

         component_name = node.get_component_name(context=Context(context))

diff --git a/tests/test_loader.py b/tests/test_loader.py
index e97e79e..1560de5 100644
--- a/tests/test_loader.py
+++ b/tests/test_loader.py
@@ -10,7 +10,6 @@ from django.template.loader import get_template

 from django_bird.loader import BIRD_TAG_PATTERN
 from django_bird.loader import BirdLoader
-from django_bird.params import Params
 from django_bird.staticfiles import assets
 from django_bird.templatetags.tags.bird import BirdNode

@@ -60,13 +59,13 @@ def test_render_template(template_name):
     "node,expected_count",
     [
         (Template("{% bird button %}Click me{% endbird %}"), 1),
-        (BirdNode(name="button", params=Params([]), nodelist=None), 1),
+        (BirdNode(name="button", attrs=[], nodelist=None), 1),
         (
             BirdNode(
                 name="button",
-                params=Params([]),
+                attrs=[],
                 nodelist=NodeList(
-                    [BirdNode(name="button", params=Params([]), nodelist=None)],
+                    [BirdNode(name="button", attrs=[], nodelist=None)],
                 ),
             ),
             1,
diff --git a/tests/test_params.py b/tests/test_params.py
index 706ba05..105017d 100644
--- a/tests/test_params.py
+++ b/tests/test_params.py
@@ -264,14 +264,17 @@ class TestParams:
         assert params.render_attrs(context) == expected

     @pytest.mark.parametrize(
-        "bits,expected",
+        "attrs,expected",
         [
             (
-                ["class='btn'"],
+                [Param(name="class", value=Value("btn", quoted=True))],
                 Params(attrs=[Param(name="class", value=Value("btn", quoted=True))]),
             ),
             (
-                ["class='btn'", "id='my-btn'"],
+                [
+                    Param(name="class", value=Value("btn", quoted=True)),
+                    Param(name="id", value=Value("my-btn", quoted=True)),
+                ],
                 Params(
                     attrs=[
                         Param(name="class", value=Value("btn", quoted=True)),
@@ -280,17 +283,20 @@ class TestParams:
                 ),
             ),
             (
-                ["disabled"],
+                [Param(name="disabled", value=Value(True))],
                 Params(attrs=[Param(name="disabled", value=Value(True))]),
             ),
             (
-                ["class=dynamic"],
+                [Param(name="class", value=Value("dynamic", quoted=False))],
                 Params(
                     attrs=[Param(name="class", value=Value("dynamic", quoted=False))]
                 ),
             ),
             (
-                ["class=item.name", "id=user.id"],
+                [
+                    Param(name="class", value=Value("item.name", quoted=False)),
+                    Param(name="id", value=Value("user.id", quoted=False)),
+                ],
                 Params(
                     attrs=[
                         Param(name="class", value=Value("item.name", quoted=False)),
@@ -300,5 +306,5 @@ class TestParams:
             ),
         ],
     )
-    def test_from_bits(self, bits, expected):
-        assert Params.from_bits(bits) == expected
+    def test_with_attrs(self, attrs, expected):
+        assert Params.with_attrs(attrs) == expected
