Skip to content

πŸ› BUG: Using JSX in attribute values causes crash with obscure error messageΒ #1048

@laymonage

Description

@laymonage

What version of @astrojs/compiler are you using?

2.10.3

What package manager are you using?

npm

What operating system are you using?

Linux

Describe the Bug

Using JSX in an attribute value causes crash with an unhelpful error message.

Example

The following component:

---
// List.astro
// Is it possible for items to be a list of *rendered* Astro components?
const { items } = Astro.props;
---

<ol class="mylist">
  {items.map((item) => <li class="mylist-item">{item}</li>)}
</ol>

When used in the following way:

---
const items = [
  {"href": "https://astro.build", "title": "Homepage", "body": "Visit the homepage."},
  {"href": "https://astro.new", "title": "New project", "body": "Try Astro."},
];
---

<List items={
	items.map((item) => (
		<div class="card">
			<a href={item.href}>
				<h2>{item.title}</h2>
				<p>{item.body}</p>
			</a>
		</div>
	))}
</List>

Causes a crash.

Even just the following use of the <List> component would cause a crash:

<List items={[<p>Hello</p>, <p>World</p>]} />

Expected result

<ol class="mylist">
  <li class="mylist-item">
    <div class="card">
      <a href="https://astro.build>
        <h2>Homepage</h2>
        <p>Visit the homepage.</p>
      </a>
    </div>
  </li>
  <li class="mylist-item">
    <div class="card">
      <a href="https://astro.new>
        <h2>New project</h2>
        <p>Try astro.</p>
      </a>
    </div>
  </li>
</ol>

Or in the case of the simple example

<ol class="mylist">
  <li class="mylist-item">
    <p>Hello</p>
  </li>
  <li class="mylist-item">
    <p>World</p>
  </li>
</ol>

Notes

Frankly, this works:

{(() => {
	const listItems = items.map((item) => (
		<div class="card">
			<a href={item.href}>
				<h2>{item.title}</h2>
				<p>{item.body}</p>
			</a>
		</div>
	));

	return <List items={listItems} />;
})()}

This works too:

{(() => {
	const examples = [<p>Hello</p>, <p>World</p>];

	return <List items={examples} />;
})()}

But this doesn't:

{(() => {
	return <List items={[<p>Hello</p>, <p>World</p>]} />;
})()}

Use case

I want to make the <List> component accepts a list of renderable elements. It will wrap each element with a li.mylist-item, and then wrap the whole thing in ol.mylist.

When I use <List>, I just want to pass the list of items that will go inside the <li>. I don't need to know about the fact that each <li> will have .mylist-item, that's just an implementation detail of <List>.

Link to Minimal Reproducible Example

https://stackblitz.com/edit/github-yujqde?file=src%2Fpages%2Findex.astro

A more elaborate example

I originally framed this as a question of migrating my React component to Astro on the Discord #general and #support channels:

See also: https://discord.com/channels/830184174198718474/1297291875002355834

Metadata

Metadata

Assignees

No one assigned

    Labels

    needs triageIssue needs to be triaged

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions