Describe the bug
When rx.accordion.item is rendered through rx.foreach, the resulting accordion items are missing the styles defined in the add_style() methods of AccordionItem, AccordionHeader, AccordionTrigger and AccordionContent. Visible symptoms in the dynamic (foreach) version:
- The chevron drops onto a new line below the header content instead of staying on the right of the row (
AccordionTrigger missing display: flex).
- There are no divider lines between accordion items (
AccordionItem missing border-top).
- The expanded content of an item is flush against the left edge with no inner padding (
AccordionContent missing padding-x and top/bottom spacers).
The same items rendered statically (without rx.foreach) render correctly.
To Reproduce
Run the code below. The top accordion uses rx.foreach, the bottom one lists the same items statically. All three symptoms above are visible side-by-side.
import reflex as rx
class BuchungenState(rx.State):
buchungen: list[dict[str, str]] = [
{"value": "kommt", "icon": "🙂", "label": "Clock In",
"label_color": "green", "time_text": "9 minutes ago", "time_bg": "#2d5a3d",
"booked_at": "01/14/2025 - 13:01:34", "open_since": "8:30"},
{"value": "aussendienst", "icon": "🚧", "label": "Field Service Start",
"label_color": "orange", "time_text": "8 minutes ago", "time_bg": "#7a3a1d",
"booked_at": "01/14/2025 - 13:02:14", "open_since": "0:08"},
{"value": "pause_anfang", "icon": "☕", "label": "Break Start",
"label_color": "yellow", "time_text": "8 minutes ago", "time_bg": "#6b5a1d",
"booked_at": "01/14/2025 - 13:02:45", "open_since": "0:08"},
{"value": "pause_ende", "icon": "🍽️", "label": "Break End",
"label_color": "yellow", "time_text": "2 minutes ago", "time_bg": "#6b5a1d",
"booked_at": "01/14/2025 - 13:08:12", "open_since": "0:02"},
]
def buchung_item(b: dict) -> rx.Component:
return rx.accordion.item(
header=rx.hstack(
rx.text(b["icon"], font_size="1.4em"),
rx.badge(b["label"], color_scheme=b["label_color"], variant="outline", size="2"),
rx.badge(b["time_text"], background=b["time_bg"], color="white", size="2"),
align="center", spacing="3",
),
content=rx.vstack(
rx.text("Booked at: ", b["booked_at"], color="cyan"),
rx.text("Open since: ", b["open_since"], color="cyan"),
spacing="2", padding="0.5em 0",
),
value=b["value"],
)
def index() -> rx.Component:
return rx.center(
rx.vstack(
# BROKEN: items rendered via rx.foreach
rx.heading("Open Bookings (dynamic via rx.foreach)", size="6"),
rx.accordion.root(
rx.foreach(BuchungenState.buchungen, buchung_item),
collapsible=True, type="multiple", variant="surface", width="100%",
),
rx.divider(margin_y="2em"),
# WORKS: same items, statically listed
rx.heading("Open Bookings (static)", size="6"),
rx.accordion.root(
*[buchung_item(b) for b in BuchungenState.buchungen.default],
collapsible=True, type="multiple", variant="surface", width="100%",
),
spacing="4", padding="2em", align="center", width="100%", max_width="600px",
),
width="100%", min_height="100vh", background="#1a1a1a",
)
app = rx.App(theme=rx.theme(appearance="dark", accent_color="teal"))
app.add_page(index)
Expected behavior
Both accordions should render identically: each item with the header laid out as a single row (badges left, chevron right), thin divider lines between items, and the expanded body shown with inner padding so it doesn't touch the left edge of the item box. The static accordion already renders this way — the dynamic (foreach) one should match.
Screenshots
Specifics (please complete the following information):
- Python Version: 3.13
- Reflex Version: reproduced on 0.8.22, 0.8.27, 0.9.1, 0.9.2, 0.9.2-post1
- OS: macOS (also reproduces on Linux)
- Browser (Optional): Firefox, Chromium (browser-independent)
Additional context
DOM diff between the two cases:
- Static (works): the compiled JSX emits each accordion sub-element with an inline
css={...} prop carrying its add_style() output. The rendered DOM gets Emotion-generated classes for AccordionItem, AccordionHeader, AccordionTrigger, AccordionContent.
- Dynamic (broken): inside the foreach-generated JSX, the same sub-elements are emitted with only their bare class name (e.g.
<button class="AccordionTrigger">) — no css prop, no Emotion class. No global CSS rule matches those class names, so each element falls back to the browser default rendering.
Suspected cause: the compile path used for components rendered inside rx.foreach appears to skip the per-instance add_style() output that the non-foreach path inlines as the css prop. This affects every primitive that relies on add_style() for its layout — Accordion is just where it's easiest to see. Other Radix primitives used inside rx.foreach are likely affected too.
Workaround: a global stylesheet that re-defines .AccordionItem, .AccordionHeader, .AccordionTrigger, .AccordionContent with the missing properties (copied from each class's add_style()) restores the layout, but obviously doesn't fix the underlying compile-path issue or the analogous issues for other primitives.
Describe the bug
When
rx.accordion.itemis rendered throughrx.foreach, the resulting accordion items are missing the styles defined in theadd_style()methods ofAccordionItem,AccordionHeader,AccordionTriggerandAccordionContent. Visible symptoms in the dynamic (foreach) version:AccordionTriggermissingdisplay: flex).AccordionItemmissingborder-top).AccordionContentmissingpadding-xand top/bottom spacers).The same items rendered statically (without
rx.foreach) render correctly.To Reproduce
Run the code below. The top accordion uses
rx.foreach, the bottom one lists the same items statically. All three symptoms above are visible side-by-side.Expected behavior
Both accordions should render identically: each item with the header laid out as a single row (badges left, chevron right), thin divider lines between items, and the expanded body shown with inner padding so it doesn't touch the left edge of the item box. The static accordion already renders this way — the dynamic (foreach) one should match.
Screenshots
Specifics (please complete the following information):
Additional context
DOM diff between the two cases:
css={...}prop carrying itsadd_style()output. The rendered DOM gets Emotion-generated classes forAccordionItem,AccordionHeader,AccordionTrigger,AccordionContent.<button class="AccordionTrigger">) — nocssprop, no Emotion class. No global CSS rule matches those class names, so each element falls back to the browser default rendering.Suspected cause: the compile path used for components rendered inside
rx.foreachappears to skip the per-instanceadd_style()output that the non-foreach path inlines as thecssprop. This affects every primitive that relies onadd_style()for its layout — Accordion is just where it's easiest to see. Other Radix primitives used insiderx.foreachare likely affected too.Workaround: a global stylesheet that re-defines
.AccordionItem,.AccordionHeader,.AccordionTrigger,.AccordionContentwith the missing properties (copied from each class'sadd_style()) restores the layout, but obviously doesn't fix the underlying compile-path issue or the analogous issues for other primitives.