GFM alignment in the delimiter row (| :--- | :---: | ---: |) is parsed by goldmark and rendered as align="left|center|right" attributes on <th>/<td>, but Confluence discards those attributes entirely. Alignment specified in markdown has no effect on the published page.
Evidence
Verified against Confluence Cloud on probe page 2913796912. Pushing a table with align="right" on a <td>, then fetching the page as ADF (GET /wiki/api/v2/pages/<id>?body-format=atlas_doc_format), shows the cell with only colspan/rowspan — no alignment of any kind. The attribute survives in body.storage but never reaches the renderer, so reading storage back is not sufficient to detect this.
What Confluence actually uses
Alignment is paragraph-level, inside the cell:
<td><p style="text-align: center;">centered</p></td>
<td><p style="text-align: right;">right</p></td>
which becomes an ADF alignment mark (align: center / align: end). Left alignment emits no attribute at all — Confluence has no explicit left. Confirmed working in <th> as well as <td>.
Fix
In internal/convert, map the GFM cell alignment onto a text-align style on a <p> wrapper inside each cell. Notes:
- Cell content must be wrapped in
<p>, which Confluence's own editor does for every cell. This changes the output of every table rather than just aligned ones, so all published pages with tables get a one-time diff and the regression goldens need regenerating.
- goldmark's
AlignNone and AlignLeft both emit nothing, since Confluence cannot distinguish them. Consequence: a source | :--- | round-trips back through read as | --- |.
storage_to_md.go's renderTable should learn to recover alignment. Confluence alignment is per-paragraph while GFM's is per-column, so a table with mixed alignment within a column cannot be represented — read will need to pick a dominant alignment per column and drop the rest.
The storage format for tables is undocumented by Atlassian; the vocabulary above was established empirically. Related: data-layout="align-start" is now emitted on all tables (internal/convert/tables.go).
GFM alignment in the delimiter row (
| :--- | :---: | ---: |) is parsed by goldmark and rendered asalign="left|center|right"attributes on<th>/<td>, but Confluence discards those attributes entirely. Alignment specified in markdown has no effect on the published page.Evidence
Verified against Confluence Cloud on probe page
2913796912. Pushing a table withalign="right"on a<td>, then fetching the page as ADF (GET /wiki/api/v2/pages/<id>?body-format=atlas_doc_format), shows the cell with onlycolspan/rowspan— no alignment of any kind. The attribute survives inbody.storagebut never reaches the renderer, so reading storage back is not sufficient to detect this.What Confluence actually uses
Alignment is paragraph-level, inside the cell:
which becomes an ADF
alignmentmark (align: center/align: end). Left alignment emits no attribute at all — Confluence has no explicit left. Confirmed working in<th>as well as<td>.Fix
In
internal/convert, map the GFM cell alignment onto atext-alignstyle on a<p>wrapper inside each cell. Notes:<p>, which Confluence's own editor does for every cell. This changes the output of every table rather than just aligned ones, so all published pages with tables get a one-time diff and the regression goldens need regenerating.AlignNoneandAlignLeftboth emit nothing, since Confluence cannot distinguish them. Consequence: a source| :--- |round-trips back throughreadas| --- |.storage_to_md.go'srenderTableshould learn to recover alignment. Confluence alignment is per-paragraph while GFM's is per-column, so a table with mixed alignment within a column cannot be represented —readwill need to pick a dominant alignment per column and drop the rest.The storage format for tables is undocumented by Atlassian; the vocabulary above was established empirically. Related:
data-layout="align-start"is now emitted on all tables (internal/convert/tables.go).