Skip to content

Commit

Permalink
Render void elements as self-closing tags (#2064)
Browse files Browse the repository at this point in the history
* Render void elements as self-closing tags

* changeset

* nit: only check void element names if there is no child content

* nit: only check void element names if there is no child content

* add tests
  • Loading branch information
Jonathan Neal committed Dec 1, 2021
1 parent b348ca6 commit 5bda895
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 1 deletion.
5 changes: 5 additions & 0 deletions .changeset/rare-jars-dance.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'astro': patch
---

Fixes an issue where void elements are rendered with opening and closing tags.
6 changes: 5 additions & 1 deletion packages/astro/src/runtime/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { serializeListValue } from './util.js';
export { createMetadata } from './metadata.js';
export type { Metadata } from './metadata';

const voidElementNames = /^(area|base|br|col|command|embed|hr|img|input|keygen|link|meta|param|source|track|wbr)$/i;

// INVESTIGATE:
// 2. Less anys when possible and make it well known when they are needed.

Expand Down Expand Up @@ -223,7 +225,9 @@ If you're still stuck, please open an issue on GitHub or join us at https://astr
// This is a custom element without a renderer. Because of that, render it
// as a string and the user is responsible for adding a script tag for the component definition.
if (!html && typeof Component === 'string') {
html = await renderAstroComponent(await render`<${Component}${spreadAttributes(props)}>${children}</${Component}>`);
html = await renderAstroComponent(
await render`<${Component}${spreadAttributes(props)}${(children == null || children == '') && voidElementNames.test(Component) ? `/>` : `>${children}</${Component}>`}`
);
}

// This is used to add polyfill scripts to the page, if the renderer needs them.
Expand Down
20 changes: 20 additions & 0 deletions packages/astro/test/astro-basic.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,26 @@ describe('Astro basics', () => {
});
});

it('Supports void elements whose name is a string (#2062)', async () => {
const html = await fixture.readFile('/input/index.html');
const $ = cheerio.load(html);

// <Input />
expect($('body > :nth-child(1)').prop('outerHTML')).to.equal('<input>');

// <Input type="password" />
expect($('body > :nth-child(2)').prop('outerHTML')).to.equal('<input type="password">');

// <Input type="text" />
expect($('body > :nth-child(3)').prop('outerHTML')).to.equal('<input type="text">');

// <Input type="select"><option>option</option></Input>
expect($('body > :nth-child(4)').prop('outerHTML')).to.equal('<select><option>option</option></select>');

// <Input type="textarea">textarea</Input>
expect($('body > :nth-child(5)').prop('outerHTML')).to.equal('<textarea>textarea</textarea>');
});

describe('preview', () => {
it('returns 200 for valid URLs', async () => {
const result = await fixture.fetch('/');
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
const {
type: initialType,
...props
} = {
...Astro.props
} as {
[K: string]: any;
};
const isSelect = /^select$/i.test(initialType);
const isTextarea = /^textarea$/i.test(initialType);
const Control = isSelect ? 'select' : isTextarea ? 'textarea' : 'input';
if (Control === 'input' && initialType) props.type = initialType;
---
<Control {...props}>{'default' in Astro.slots ? <slot /> : null}</Control>
16 changes: 16 additions & 0 deletions packages/astro/test/fixtures/astro-basic/src/pages/input.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
import Input from '../components/Input.astro';
---

<html>
<head>
<!-- Head Stuff -->
</head>
<body>
<Input />
<Input type="password" />
<Input type="text" />
<Input type="select"><option>option</option></Input>
<Input type="textarea">textarea</Input>
</body>
</html>

0 comments on commit 5bda895

Please sign in to comment.