Curly braces open a hole in the markup that holds one JavaScript expression — a value, not a statement. An if or a for inside braces is a syntax error; a ternary, a &&, a .map() or a function call is fine. The same braces work as a child, where the result is rendered, and as an attribute value, where it is passed as a prop. A bare attribute such as disabled means disabled={true}, and {...obj} spreads an object's own properties into the attribute list, left to right, so a later attribute wins.
Attribute names are object keys and follow JavaScript rules: class becomes className, for becomes htmlFor, hyphenated DOM properties become camelCase (strokeWidth, tabIndex). Only data-* and aria-* keep their dashes, because they pass through to the DOM verbatim. The style attribute takes an object, not a string: camelCase keys, and a number gets px unless the property is unitless (lineHeight, zIndex).
const product = { name: 'Mechanical keyboard', price: 89.9, stock: 3 };
const badge = { padding: '2px 8px', borderRadius: 10, '--tint': '#2e7d32',
background: product.stock ? '#e8f5e9' : '#ffebee' };
const link = { href: 'https://example.com/kb', 'aria-label': 'Product page' };
const row = (
<p data-sku="KB-01">
<a {...link}>{product.name.toUpperCase()}</a>{' '}
<b>{product.price.toFixed(2)} USD</b>{' '}
<span style={badge}>{product.stock} left</span>
</p>
);borderRadius: 10 reaches the DOM as 10px, while the custom property --tint passes through untouched. {' '} forces a space JSX would otherwise drop: the compiler strips whitespace at the start and end of each line, so without it the link would butt against the price.