---
title: 'Proximity and Grouping'
source: 'https://academia.sh/en/courses/interface-fundamentals/proximity-and-grouping'
course: 'Fundamentals of Interface Design'
language: en
updated: '2026-08-17T18:11:08+00:00'
license: 'CC BY-SA 4.0'
---

# Proximity and Grouping

How relationship is declared through space; grouping is established by spacing ratio rather than absolute space, and nested grouping levels are audited numerically.

The previous lesson dealt with separating elements from one another: which element is
read first, and on which channels that order is expressed. The interface's second job is
the reverse. In a catalog record, the title, the author's name, and the shelf code are
drawn separately but belong to the same book. The next record's title sits only a few
pixels below and belongs to a different book. On screen, what tells these two situations
apart?

The answer is not a line or a frame but space. This lesson shows how space establishes a
relationship, why that relationship depends not on an absolute pixel value but on the
**ratio** between gaps, and how that ratio is audited.

## Proximity Declares a Relationship

**Proximity** is the tendency for elements standing close to one another to be perceived
as a single unit. This tendency is a member of a group known in perceptual psychology as
the **Gestalt principles**, which also includes elements that look alike being perceived
together (**similarity**) and elements sharing a common background or frame being
perceived together (**common region**).

These principles matter for interface design in a practical, not a theoretical, sense:
they do not offer a choice, they impose a constraint. The moment elements are placed on
a plane, they are grouped. The designer's decision is not "should I group these" but
"does the perceived grouping match the intended grouping." When no space is assigned,
grouping does not disappear; a random grouping settles in instead.

There is a ranking of strength among the proximity principles. When two elements are
close but differ in color, proximity beats similarity: the elements are read as a single
group. In a catalog record, if the title is dark and bold while the author's name is
pale and normal weight, the two are still perceived as a single record when only 4
pixels separate them. This means hierarchy and grouping do not coincide: elements inside
a group can differ in weight from one another; what carries the group's identity is the
space.

## Grouping Is Established by Ratio, Not Absolute Space

Proximity is a relative measure. The sentence "24 pixels of space separates the records"
is neither true nor false on its own; it cannot be evaluated without knowing how many
pixels of space sit inside the record. If the internal spacing is 4 pixels, 24 pixels is
a clear boundary; if the internal spacing is 20 pixels, the same 24 pixels separates
nothing.

Making this auditable requires a criterion. This course adopts the following one: a gap
counts as a group boundary if it is **at least twice** the smallest gap in the same
stack. The program below tests two different spacing decisions for the catalog results
list against this criterion.

```js
// 02-grouping.mjs — checks grouping in a vertical stack by gap ratio

// Two rows of the catalog result list: each record carries a title + author + metadata.
// Each item is given as (name, height, topGap); topGap is its distance from the previous item.
const designA = [
  { name: "record-1 title", height: 24, topGap: 0, group: 1 },
  { name: "record-1 author", height: 20, topGap: 4, group: 1 },
  { name: "record-1 metadata", height: 18, topGap: 4, group: 1 },
  { name: "record-2 title", height: 24, topGap: 24, group: 2 },
  { name: "record-2 author", height: 20, topGap: 4, group: 2 },
  { name: "record-2 metadata", height: 18, topGap: 4, group: 2 },
];

const designB = [
  { name: "record-1 title", height: 24, topGap: 0, group: 1 },
  { name: "record-1 author", height: 20, topGap: 12, group: 1 },
  { name: "record-1 metadata", height: 18, topGap: 12, group: 1 },
  { name: "record-2 title", height: 24, topGap: 16, group: 2 },
  { name: "record-2 author", height: 20, topGap: 12, group: 2 },
  { name: "record-2 metadata", height: 18, topGap: 12, group: 2 },
];

// Course criterion: a gap counts as a group boundary if it is SEPARATION_RATIO times
// the smallest gap in the stack. Below a ratio of 2 the boundary is ambiguous.
const SEPARATION_RATIO = 2;

function groupItems(items) {
  const gaps = items.slice(1).map((o) => o.topGap);
  const smallest = Math.min(...gaps);
  const groups = [[items[0].name]];
  const ratios = [];
  for (let i = 1; i < items.length; i++) {
    const ratio = items[i].topGap / smallest;
    ratios.push({ name: items[i].name, gap: items[i].topGap, ratio });
    if (ratio >= SEPARATION_RATIO) groups.push([items[i].name]);
    else groups[groups.length - 1].push(items[i].name);
  }
  return { smallest, ratios, groups };
}

function report(title, items) {
  const { smallest, ratios, groups } = groupItems(items);
  const intended = new Set(items.map((o) => o.group)).size;
  console.log(`${title}  (smallest gap: ${smallest}px, threshold ratio: ${SEPARATION_RATIO})`);
  for (const o of ratios) {
    const boundary = o.ratio >= SEPARATION_RATIO ? "BOUNDARY" : "in group";
    console.log(
      `  ${o.name.padEnd(18)} above ${String(o.gap).padStart(2)}px  ratio ${o.ratio
        .toFixed(2)
        .padStart(5)}  ${boundary}`
    );
  }
  console.log(`  intended group count: ${intended}   perceived group count: ${groups.length}`);
  groups.forEach((g, i) => console.log(`    group ${i + 1}: ${g.join(", ")}`));
  console.log("");
}

report("design A  in-group 4px / separator 24px", designA);
report("design B  in-group 12px / separator 16px", designB);
```

```
design A  in-group 4px / separator 24px  (smallest gap: 4px, threshold ratio: 2)
  record-1 author    above  4px  ratio  1.00  in group
  record-1 metadata  above  4px  ratio  1.00  in group
  record-2 title     above 24px  ratio  6.00  BOUNDARY
  record-2 author    above  4px  ratio  1.00  in group
  record-2 metadata  above  4px  ratio  1.00  in group
  intended group count: 2   perceived group count: 2
    group 1: record-1 title, record-1 author, record-1 metadata
    group 2: record-2 title, record-2 author, record-2 metadata

design B  in-group 12px / separator 16px  (smallest gap: 12px, threshold ratio: 2)
  record-1 author    above 12px  ratio  1.00  in group
  record-1 metadata  above 12px  ratio  1.00  in group
  record-2 title     above 16px  ratio  1.33  in group
  record-2 author    above 12px  ratio  1.00  in group
  record-2 metadata  above 12px  ratio  1.00  in group
  intended group count: 2   perceived group count: 1
    group 1: record-1 title, record-1 author, record-1 metadata, record-2 title, record-2 author, record-2 metadata
```

Both designs share the same goal: two records, two groups. Design A produces it; design
B does not. What stands out is that design B is **more spacious**. Its total spacing is
greater — it leaves 16 pixels between records — and yet it erases the record boundary.
Adding space does not improve grouping; **differentiating** space does.

This also explains why spacing decisions cannot be made one at a time. The decision to
place 16 pixels between records cannot be evaluated in isolation, because its meaning
depends on neighboring decisions. Spacing decisions are made as a set.

## Nested Grouping Levels

The catalog screen does not have a single grouping level. The title and the author's
name are grouped at one level, record blocks at a level above that, records at a level
above that, and the screen's sections at the top. Every level must be distinguishable
from the level below it; otherwise one rung of the hierarchy becomes invisible.

```js
// 02-nested.mjs — checks the gap ratio of nested grouping levels

// Four grouping levels on the catalog screen, innermost to outermost.
const levels = [
  { name: "within row (title-author)", gap: 4 },
  { name: "blocks within record", gap: 8 },
  { name: "between records", gap: 24 },
  { name: "between sections", gap: 48 },
];

const SEPARATION_RATIO = 2;

console.log("level                      gap  ratio to level below  status");
for (let i = 0; i < levels.length; i++) {
  const l = levels[i];
  if (i === 0) {
    console.log(`${l.name.padEnd(26)} ${String(l.gap).padStart(4)}px  ${"-".padStart(20)}  base`);
    continue;
  }
  const ratio = l.gap / levels[i - 1].gap;
  const status = ratio >= SEPARATION_RATIO ? "separates" : "AMBIGUOUS";
  console.log(
    `${l.name.padEnd(26)} ${String(l.gap).padStart(4)}px  ${ratio.toFixed(2).padStart(20)}  ${status}`
  );
}
```

```
level                      gap  ratio to level below  status
within row (title-author)     4px                     -  base
blocks within record          8px                  2.00  separates
between records              24px                  3.00  separates
between sections             48px                  2.00  separates
```

Four levels, a base spacing of 4 pixels, an outermost spacing of 48 pixels. Every ratio
between them sits above two, so every level is distinguishable from the one below it.
The real finding here is not the numbers themselves but their **multiplicative**
progression: 4, 8, 24, 48. An additive sequence (4, 8, 12, 16) cannot do the same job,
because toward the outer levels the ratios rapidly approach one.

This observation also sets a limit on the number of grouping levels. If the base spacing
is 4 pixels and every level must be at least twice the one below it, six levels require
$4 \cdot 2^{5} = 128$ pixels at the outermost level. Considering how expensive 128
vertical pixels are on a screen, the practical number of grouping levels turns out to sit
around four. As with hierarchy levels, the fix here is not adding a level but removing
one that is not needed.

## Space or a Frame

The common-region principle is a second way to group: enclosing elements in a frame or
giving them a shared background color also turns them into a single unit. This route is
stronger than proximity — a frame beats proximity: two elements that are far apart
inside a box are perceived as more related than a nearby element outside the box.

Being stronger does not make it the default choice. A frame's cost is visual noise. If
every record in a twenty-record results list is framed, 20 rectangles — 80 lines — are
added to the screen. None of these lines carries information; every one of them just
declares the record boundary. If the same boundary were declared with space, no line
would be added to the screen at all. Space is the only grouping tool that works with
zero ink.

The criterion can be written as follows: **common region is reserved for establishing a
relationship that proximity cannot build.** There are three situations where proximity
falls short. The first is when elements are not separated horizontally and vertically;
giving a table's rows space would inflate row height, so separating them with a
background color can be cheaper. The second is when a group carries a function different
from the rest of the screen; the section holding the borrowing action is an action area,
and separating it from the reading area with space alone loses information. The third is
when the group is a scrollable area; a scroll area with no visible boundary hides where
the content ends.

## The Mislinked Label

The most expensive form of a proximity error appears in the section holding the search
field. The catalog interface has three filter fields: publication year, language, and
material type. Above each field is a label, and below it a description line.

If the space between the label and the field is 8 pixels, the space between the field
and the description is 8 pixels, and the space between the description and the next
label is 12 pixels, the ratio to the smallest gap is 12 / 8 = 1.5, which stays below the
threshold. The result is three separate filters turning into a single block; the reader
cannot tell which description belongs to which field from the space and has to find out
by trial.

The correct arrangement is to bind the label to the field and separate the group from
the outside: label–field 4 pixels, field–description 4 pixels, between groups 24 pixels.
The ratio becomes 24 / 4 = 6. This arrangement looks more "cramped" on paper, but it
reads more clearly on screen, because the cramping sits inside the group while the
spaciousness sits between groups.

The same rule applies to the label's position. When the label is placed to the left of
the field, the horizontal space between the label and its own field must be smaller than
the vertical space between the label and the next row. In a grouping that operates on
two axes, the ratio criterion is tested separately on each axis.

## Summary

- Proximity is the perception of nearby elements as a single unit; elements are grouped
  the moment they are placed on a plane, so the question is not whether grouping exists
  but whether it matches the intended grouping.
- Grouping is established by the ratio between neighboring gaps, not by an absolute
  spacing value; this course's criterion is that a group boundary is at least twice the
  smallest gap.
- Adding space does not improve grouping; differentiating space does. A design with more
  total spacing can group more weakly.
- Nested grouping levels progress multiplicatively; an additive sequence erases
  boundaries at the outer levels because it drives the ratio toward one.
- Common region is stronger than proximity but carries an ink cost; it is reserved for
  relationships proximity cannot build.
- Spacing decisions are made as a set rather than one at a time, because a gap's meaning
  depends on its neighboring gaps.

## Next Step

This lesson dealt with establishing relationships. What remains is establishing
distinction with **restraint**. In the previous two lessons, distinction was always
treated in one direction: bringing an element forward. But emphasis is a budget; every
emphasized element on screen reduces the share left for the other emphasized elements.
The next lesson computes visual weight from area and luminance difference, extracts the
emphasis shares on the catalog screen, and uses numbers to show why three primary
actions leave none of them primary.
