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.
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 rendered | From a <BlendingSetting> attached to the Group. Captured for a whole-group composite. |
| BlendMode | Normal | Multiply | Screen | … | Parsed, not rendered | Blend mode for the group as a unit. |
| DropShadow | <DropShadowSetting> | Parsed, not 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.