VML
A VML shape for Windows Outlook (Word), which cannot draw a background image, a gradient or a rounded box in CSS: the base the primitives that need one build on, as Maizzle's <Vml> is. resolveVml in lib/vml.ts validates the props and writes the markup; this puts the content between it.
Examples
VML
A background image, a gradient and a rounded panel, drawn for Windows Outlook in VML behind content every client shows.
17.6 KB built. Open the built email (opens in a new tab)
const image = 'https://digitalnsw.github.io/images/placeholder/email-placeholder.jpg';
<NswLayout title='VML'>
<NswColumns padding={false}>
<NswColumn>
<table role='presentation' width='100%' cellPadding='0' cellSpacing='0'>
<tbody>
<tr>
<td
valign='top'
style={{
backgroundColor: '#949494',
backgroundImage: 'url(' + image + ')',
backgroundSize: 'cover',
backgroundPosition: 'center',
}}
>
<NswVml
width={layout.width}
height={299}
src={image}
color='#949494'
inset={[0, 48, 0, 48]}
>
<table role='presentation' width='100%' cellPadding='0' cellSpacing='0'>
<tbody>
<tr>
<td style={{ padding: '48px' }}>
<table
role='presentation'
cellPadding='0'
cellSpacing='0'
bgcolor='#ffffff'
style={{ backgroundColor: '#ffffff' }}
>
<tbody>
<tr>
<td width='24' style={{ width: '24px' }} />
<td style={{ padding: '24px 0' }}>
<NswText as='h1' type='headline-md'>
A background image
</NswText>
<NswText>
Drawn in Windows Outlook by a VML frame fill behind this card.
</NswText>
</td>
<td width='24' style={{ width: '24px' }} />
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</NswVml>
</td>
</tr>
</tbody>
</table>
</NswColumn>
</NswColumns>
<NswColumns padding={false}>
<NswColumn>
<table role='presentation' width='100%' cellPadding='0' cellSpacing='0'>
<tbody>
<tr>
<td
style={{
backgroundColor: '#002664',
backgroundImage: 'linear-gradient(90deg, #002664, #146cfd)',
}}
>
<NswVml
width={layout.width}
type='gradient'
color='primary-800'
color2='primary-600'
angle={90}
inset={[0, 48, 0, 48]}
>
<table role='presentation' width='100%' cellPadding='0' cellSpacing='0'>
<tbody>
<tr>
<td style={{ padding: '48px' }}>
<NswText as='h2' type='headline-md' color='white'>
A gradient
</NswText>
<NswText color='white'>
A VML gradient fill in Windows Outlook, a CSS gradient everywhere
else.
</NswText>
</td>
</tr>
</tbody>
</table>
</NswVml>
</td>
</tr>
</tbody>
</table>
</NswColumn>
</NswColumns>
<NswColumns>
<NswColumn>
<NswSpacer height={48} />
<table role='presentation' width='100%' cellPadding='0' cellSpacing='0'>
<tbody>
<tr>
<td
style={{
backgroundColor: '#f5f5f5',
border: '1px solid #dcdfe0',
borderRadius: '8px',
}}
>
<NswVml
shape='roundrect'
arcSize={0.08}
fillColor='grey-100'
strokeColor='grey-300'
strokeWeight={1}
inset={[0, 24, 0, 24]}
>
<table role='presentation' width='100%' cellPadding='0' cellSpacing='0'>
<tbody>
<tr>
<td style={{ padding: '24px' }}>
<NswText as='h2' type='headline-sm'>
A rounded panel
</NswText>
<NswText>
A VML roundrect in Windows Outlook, a border radius elsewhere.
</NswText>
</td>
</tr>
</tbody>
</table>
</NswVml>
</td>
</tr>
</tbody>
</table>
<NswSpacer height={48} />
</NswColumn>
</NswColumns>
</NswLayout>Props
| Prop | Type | Default | Description |
|---|---|---|---|
layout | Layout | — | The layout the default width is drawn from: the document's (handed on by <NswLayout layout>) unless the shape is given one of its own, and the NSW defaults outside a document. Only the default width (layout.width) is drawn from it; an explicit width still wins. |
shape | VmlShape | rect | The shape: rect, roundrect (corners from arcSize), oval or line (from from to to, no content). Default rect. |
href | string | — | Where the shape links to in Word: the whole shape is then the click target. Other clients see only the content, so link that too. |
width | VmlWidth | the content width of a full-width column (layout.width less the row padding either side) | The shape's width: whole px, or 'page' for the page's full width (Word's mso-width-percent: 1000), which is only for a full-bleed background — Word measures it against the page, not the row, so inside a row it spills past the row. Not for a line. Default the content width of a full-width column (layout.width less the row padding either side). |
height | number | — | The shape's height in whole px. Left out, the shape grows to fit its content (mso-fit-shape-to-text). Not for a line. |
arcSize | number | — | A roundrect's corner radius as a fraction of its shorter side, from 0 to 1 (0.1 on a 40px-tall shape is a 4px radius). Only for a roundrect. |
from | readonly [number, number] | — | Where a line starts: [x, y] in whole px. Required for a line, and only for one. |
to | readonly [number, number] | — | Where a line ends: [x, y] in whole px. Required for a line, and only for one. |
fillColor | ColorValue | — | The shape's own fill: a theme colour name or a hex literal, or 'transparent' for none; anything else throws (see resolveColor). Also what shows where a fill image has not loaded. Word's dark mode never recolours a VML fill, though it recolours the text on it. Not for a line. |
strokeColor | ColorValue | — | The outline's colour: a theme colour name or a hex literal; 'transparent' and anything else throws. Left out, no outline — except a line, which needs it. |
strokeWeight | number | VML's own, 1px | The outline's width in whole px, written as VML points. Only with a strokeColor. Default VML's own, 1px. |
type | VmlFillType | frame when there is a src, VML's solid otherwise | How the <v:fill> paints: solid, gradient, gradientradial, tile, pattern or frame. Default frame when there is a src, VML's solid otherwise. |
src | string | — | The fill image's URL. |
color | ColorValue | — | The fill's colour, a gradient's first: a theme colour name or a hex literal; 'transparent' and anything else throws. |
color2 | ColorValue | — | A gradient's second colour: a theme colour name or a hex literal; 'transparent' and anything else throws. |
opacity | number | — | The fill's opacity, from 0 to 1. |
angle | number | — | A gradient's direction in CSS linear-gradient degrees, from 0 to 360: 0 runs color at the bottom to color2 at the top, 90 from left to right. Written as VML's own angle, which turns the other way. |
focus | number | — | Where a gradient's colours meet, as a percentage from -100 to 100 (50 puts the second colour in the middle). |
focusSize | readonly [number, number] | — | A radial gradient's focus size, [x, y] as fractions of the shape. |
focusPosition | readonly [number, number] | — | A radial gradient's focus position, [x, y] as fractions of the shape. |
size | readonly [number, number] | — | The fill image's size, [width, height] in whole px. |
origin | readonly [number, number] | — | The fill image's origin, [x, y] as fractions of the image (-0.5 is its left or top edge). Wins over backgroundPosition. |
position | readonly [number, number] | — | Where the fill image's origin sits, [x, y] as fractions of the shape. Wins over backgroundPosition. |
backgroundPosition | VmlBackgroundPosition | — | The fill image's placement in words, vertical first ('top left', 'center center'): sets origin and position together. |
aspect | VmlAspect | — | How the fill image keeps its proportions: atleast (covers the shape) or atmost (fits inside it). |
inset | readonly [number, number, number, number] | none | Space between the shape's edge and its content in Word, [top, right, bottom, left] in whole px. In CSS's order, written in VML's (left, top, right, bottom). Word keeps a cell's top and bottom padding inside the text box but drops its left and right, so give the content's side padding here too. Not for a line. Default none. |