Groups
How an IDML Group clusters page items, how its transform and transparency reach the members, and what the renderer does inside one.
A Group is the one page item that holds no marks of its own — it is a container that clusters other page items so they move as one.
In short: A Group is the IDML page item that holds no marks of its own. It
is a container: its children are the page items it clusters so they can be
moved, scaled, rotated, or made translucent as a single object. On disk a group's
members are written as child elements of the <Group>, and the group's
ItemTransform composes onto each of them. This page explains how membership and
the composed transform work, how group-level transparency is captured, and what
our renderer does inside a group today.
A Group is the one page item that holds no marks of its own. It is a
container: its children are the page items it clusters so they can be moved,
scaled, rotated, or made translucent as a single object. In the IDML on disk a
group's members are written as child elements of the <Group>, exactly the way
the page-item reference shapes appear as
children of a <Spread>.
The example below is the smallest meaningful group: two filled rectangles wrapped so a single transform places the pair.
A Group around two rectangles. The group's ItemTransform moves both at once.
Spreads/Spread_uspread.xml<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<idPkg:Spread xmlns:idPkg="http://ns.adobe.com/AdobeInDesign/idml/1.0/packaging" DOMVersion="20.0">
<Spread Self="uspread" PageCount="1" BindingLocation="0" ShowMasterItems="true" AllowPageShuffle="true" ItemTransform="1 0 0 1 0 0">
<Page Self="upage" Name="1" AppliedMaster="umaster" ItemTransform="1 0 0 1 0 0" GeometricBounds="0 0 841.89 595.276" MasterPageTransform="1 0 0 1 0 0"/>
<Group Self="ugroup" ItemTransform="1 0 0 1 100 120" AppliedObjectStyle="ObjectStyle/$ID/[None]" Visible="true" Name="$ID/">
<Rectangle Self="urect1" ContentType="GraphicType" AppliedObjectStyle="ObjectStyle/$ID/[None]" Visible="true" Name="$ID/" ItemTransform="1 0 0 1 0 0" FillColor="Color/Red" StrokeColor="Swatch/None" StrokeWeight="0">
<Properties>
<PathGeometry>
<GeometryPathType PathOpen="false">
<PathPointArray>
<PathPointType Anchor="0 0" LeftDirection="0 0" RightDirection="0 0"/>
<PathPointType Anchor="0 180" LeftDirection="0 180" RightDirection="0 180"/>
<PathPointType Anchor="180 180" LeftDirection="180 180" RightDirection="180 180"/>
<PathPointType Anchor="180 0" LeftDirection="180 0" RightDirection="180 0"/>
</PathPointArray>
</GeometryPathType>
</PathGeometry>
</Properties>
</Rectangle>
<Rectangle Self="urect2" ContentType="GraphicType" AppliedObjectStyle="ObjectStyle/$ID/[None]" Visible="true" Name="$ID/" ItemTransform="1 0 0 1 220 80" FillColor="Color/Blue" StrokeColor="Swatch/None" StrokeWeight="0">
<Properties>
<PathGeometry>
<GeometryPathType PathOpen="false">
<PathPointArray>
<PathPointType Anchor="0 0" LeftDirection="0 0" RightDirection="0 0"/>
<PathPointType Anchor="0 180" LeftDirection="0 180" RightDirection="0 180"/>
<PathPointType Anchor="180 180" LeftDirection="180 180" RightDirection="180 180"/>
<PathPointType Anchor="180 0" LeftDirection="180 0" RightDirection="180 0"/>
</PathPointArray>
</GeometryPathType>
</PathGeometry>
</Properties>
</Rectangle>
</Group>
</Spread>
</idPkg:Spread>
Membership and the composed transform
When the parser meets a <Group> it records the group and then walks its
children. Each member — Rectangle, Oval, GraphicLine, Polygon,
TextFrame, or a nested Group — is lifted out onto the spread's normal
page-item lists, but with the group's ItemTransform already composed onto
the member's own transform. Nesting composes through every level: a member two
groups deep ends up with outer ∘ inner ∘ member.
The upshot is that downstream layers do not have to special-case groups to place
things correctly — every member already carries its final transform. The
original Group record is kept alongside (with its member list and its own
un-composed transform) so a renderer that wants to bracket the cluster — for a
shared opacity, blend mode, or drop shadow — still can. Both rectangles in the
example paint at their composed positions; nothing is dropped.
Group-level transparency
A group can carry a transparency block that applies to all of its members at once — the reason to group shapes in the first place is often a single uniform effect:
| Attribute · Group transparency (from BlendingSetting / DropShadowSetting) | Type / values | Support | Notes |
|---|---|---|---|
| Opacity | double (0–100) | Parsed, not yet rendered | From a <BlendingSetting> attached to the Group. Captured for a whole-group composite. |
| BlendMode | Normal | Multiply | Screen | … | Parsed, not yet rendered | Blend mode for the group as a unit. |
| DropShadow | <DropShadowSetting> | Parsed, not yet rendered | A shadow cast by the flattened group, captured against the group rather than each child. |
The parser routes a <DropShadowSetting> or <BlendingSetting> that sits
directly under a <Group> (not under a StrokeTransparencySetting or
ContentTransparencySetting wrapper) into that group's transparency record, so
the renderer can one day bracket the member range with a single transparency
group instead of compositing each shape independently.
What the renderer does inside a group today
Group members render: the lift-and-compose pass means each shape paints at its
correct place, as the example proves. What is not yet honoured is the
group-level transparency block — opacity, blend mode, and the group drop shadow
are parsed and attached to the Group record but the whole-group composite that
would apply them is still on the roadmap.
One historical note for readers of the parser: a skipped_nested_frames counter
exists on the spread record and is surfaced by paged-inspect. It dates from an
earlier pass that dropped group-nested text frames; the current parser lifts
those frames out instead, so the counter stays 0 (spread.rs:116–119). If you
see it report a non-zero value, that is a signal worth investigating, not the
expected case.
Frequently asked questions
What does a Group do in IDML?
A Group clusters several page items so a single transform, opacity, or effect
can apply to all of them at once. It holds no fill or stroke of its own — its only
content is the members written as child elements of the <Group>.
How does a group's transform reach its members?
When the parser meets a <Group> it lifts each member out onto the spread's
normal page-item lists with the group's ItemTransform already composed onto
the member's own transform. Nesting composes through every level, so a member two
groups deep ends up with outer ∘ inner ∘ member — and downstream layers never
have to special-case groups to place things correctly.
Does the renderer apply group-level opacity and drop shadows?
Not yet. A group's Opacity, BlendMode, and drop shadow are parsed and attached
to the Group record, but the whole-group composite that would apply them is
still on the roadmap; the members themselves render at their correct composed
positions today.
Text frames
The IDML TextFramePreference block — InsetSpacing, VerticalJustification, FirstBaselineOffset, and AutoSizingType.
Typography
What the renderer does with type once the parser hands it text runs — resolving fonts, shaping and spacing glyphs, breaking lines, and placing drop caps and tabs — with an honest map of where each construct stands.