Hollow Square Border Number in JavaScript

Beginner
⏱️ 10 min read
📚 Updated: Sep 2026
🎯 3 Code Examples
🚀 Live Preview
Nested Loops + Formatting

What You’ll Learn

Program 59 prints a hollow square border: a 5×5 grid where only the boundary shows consecutive numbers 1–16 and the inside stays blank — a shift from Program 58’s diagonal diamond to rectangular border logic. This tutorial covers border detection, fixed-width formatting, separate side counters, a live preview, worked JavaScript examples, edge cases, and complexity.

Shape Rule

Hollow border

Only cells on the border print numbers — top, right, bottom, and left sides use different counter sequences.

Nested Loops

i, j = 1..5

for (let i = 1; i <= 5; i++) { for (let j = 1; j <= 5; j++) } — visit every cell in the 5×5 grid.

Border Checks

if / elif

i === 1, j === 5, i === 5, j === 1 — detect which side of the border the cell belongs to.

Side Counters

k, l, m

k = 6 (right), l = 13 (bottom), m = 16 (left) — track values for non-top sides.

Fixed Width

:3d

String(value).padStart(3, " ") and " " for inner cells — columns stay aligned.

O(n²)

Complexity

Every cell in the n×n grid is visited once — total work grows as O(n²).

Introduction

A hollow square border number pattern prints consecutive numbers only on the boundary of a square grid, leaving the interior blank. For a 5×5 square, the top row shows 1..5, the right column continues 6..9, the bottom row shows 13..9, and the left column finishes with 16..13.

In JavaScript use nested loops over rows and columns, then branch with if / else if to detect border sides. Use String(value).padStart(3, " ") for numbers and three spaces for inner cells.

Why it matters?

It bridges Program 58’s diagonal symmetry to rectangular grids — combining border detection, multiple counters, and fixed-width formatting.

Key Highlights

Top row

i == 1 prints j (1..5).

Right column

j == 5 prints k++ (6..9).

vs Program 58

Program 58 uses diagonal mirror loops; Program 59 uses rectangular border checks.

Series Foundation

Follow Program 58; continue to Program 60 next.

In short: nested i, j loops, border if checks, counters k, l, m, fixed width 3, then console.log(line) per row.

📝 Problem & Approach

Print a 5×5 hollow square where the border shows numbers 1–16 clockwise and inner cells are blank spaces of width 3.

JavaScript
// 5×5 hollow border (numbers 1..16)
//1  2  3  4  5
//16          6
//15          7
//14          8
//13 12 11 10 9

Inputs & Outputs

ItemTypeDescription
Grid sizeint5×5 in the fixed demo — 25 cells total, 16 on the border.
i (outer)intRow index — runs 1 to 5.
j (inner)intColumn index — runs 1 to 5.
kintRight column counter — starts at 6, increments.
lintBottom row counter — starts at 13, decrements.
mintLeft column counter — starts at 16, decrements.

Minimal workflow

Pseudocode
init k, l, m for right, bottom, left sides
for i from 1 to n:
    for j from 1 to n:
        if top row: print j
        else if right column: print k++
        else if bottom row: print l--
        else if left column: print m--
        else: print three spaces
    print newline

Approach comparison

ApproachIdeaBest for
if / elif chainDetect top, right, bottom, left border per cellLearning and interviews
Separate countersk, l, m for non-top sidesClockwise numbering
Fixed-width formatString(value).padStart(3, " ") for numbers, " " insideAligned columns
Configurable sizeRead n from inputFlexible grid size
Compact tracen = 3 on paper firstQuick dry-runs before 5×5 demo

⚡ Quick Reference

GoalPattern
Outer loopfor (let i = 1; i <= 5; i++)
Inner loopfor (let j = 1; j <= 5; j++)
Top rowif (i === 1) line += String(j).padStart(3, " ")
Right columnelse if (j === 5) line += String(k).padStart(3, " "); k++
Bottom rowelse if (i === 5) line += String(l).padStart(3, " "); l--
Left columnelse if (j === 1) line += String(m).padStart(3, " "); m--
Inner cellelse line += " "
Program 58 contrastProgram 58 uses diagonal mirror; Program 59 uses rectangular border checks

📋 Fixed 5×5 vs Configurable vs Compact Trace

Same hollow border idea — three ways to set grid size and trace the logic.

Fixed 5×5
n = 5

Numbers 1–16 on border

User input
parseInt(prompt())

Read square size from console

Compact trace
n = 3

9-cell grid dry-run

Top side
i == 1

Print column index j

Inner
"   "

Three spaces, width 3

Context

When This Pattern Shows Up

Reach for this pattern when teaching 2D grids, border detection, fixed-width formatting, and multiple counters.

  1. Post Program 58 exercise

    Natural follow-up after Program 58’s diamond — introduces rectangular grids and border-only printing.

  2. Grid formatting drills

    Fixed-width String(value).padStart(3, " ") keeps columns aligned — essential for multi-digit borders.

  3. Multiple counters

    Separate k, l, m for right, bottom, left — concrete state-tracking practice.

  4. Gateway to Program 60

    Compare this hollow border with the next pattern in the series.

  5. Not a UI layout tool

    This is a console teaching pattern — not how you build modern app screens.

Key benefit: one small program that locks in border checks, formatting, and O(n²) grid thinking.

🔮 Live Preview

Choose row count between 3 and 9 and draw the centered hollow square border number pattern in the browser.

Try 4, 5, or 7. Max up to 7 in this preview.

Live result
Press "Draw pattern".

Examples Gallery

Three complete JavaScript programs — fixed 5×5 border, configurable size, and a compact 3×3 trace demo. Click View Output to reveal sample console results, or Try it Yourself to run in the browser.

📚 Getting Started

Print a 5×5 hollow border with numbers 1–16 clockwise — top, right, bottom, and left sides with separate counters.

Example 1 — Fixed 5×5 Border

Hard-coded grid — use if / else if to detect border sides and padStart(3) formatting for alignment.

JavaScript
let k = 6;
let l = 13;
let m = 16;

for (let i = 1; i <= 5; i++) {
  let line = "";

  for (let j = 1; j <= 5; j++) {
    if (i === 1) {
      line += String(j).padStart(3, " ");
    } else if (j === 5) {
      line += String(k).padStart(3, " ");
      k++;
    } else if (i === 5) {
      line += String(l).padStart(3, " ");
      l--;
    } else if (j === 1) {
      line += String(m).padStart(3, " ");
      m--;
    } else {
      line += "   ";
    }
  }

  console.log(line);
}
Try it Yourself

How It Works

Row 1 prints j for every column. Rows 2–4 print m-- on the left, k++ on the right, and spaces inside. Row 5 prints l-- across the bottom.

📈 User Input

Read square size with prompt() and Number.isFinite validation.

Example 2 — Configurable Square Size

Read n with prompt() — append column index on border cells, spaces inside. Counter rules can be customized for larger grids.

JavaScript
const nInput = prompt("Enter square size (n):");
const n = parseInt(nInput, 10);

if (!Number.isFinite(n) || n < 2) {
  console.log("Please enter an integer >= 2.");
} else {
  for (let i = 1; i <= n; i++) {
    let line = "";

    for (let j = 1; j <= n; j++) {
      const isBorder = i === 1 || i === n || j === 1 || j === n;

      if (isBorder) {
        line += String(j).padStart(3, " ");
      } else {
        line += "   ";
      }
    }

    console.log(line);
  }
}
Try it Yourself

How It Works

Uses a simple isBorder flag instead of side-specific counters — good starting point before adding clockwise numbering for arbitrary n.

⚡ Compact Trace

Smaller 3×3 grid for quick tracing on paper or in interviews.

Example 3 — Compact 3×3 Border

Use n = 3 with scaled counter starts — trace all four sides before scaling to 5×5.

JavaScript
const n = 3;
let k = n + 1;
let l = 3 * n - 2;
let m = 4 * (n - 1);

for (let i = 1; i <= n; i++) {
  let line = "";

  for (let j = 1; j <= n; j++) {
    if (i === 1) {
      line += String(j).padStart(3, " ");
    } else if (j === n) {
      line += String(k).padStart(3, " ");
      k++;
    } else if (i === n) {
      line += String(l).padStart(3, " ");
      l--;
    } else if (j === 1) {
      line += String(m).padStart(3, " ");
      m--;
    } else {
      line += "   ";
    }
  }

  console.log(line);
}
Try it Yourself

How It Works

With only nine cells and one inner gap, you can trace every border branch on paper before running the full 5×5 demo.

🧠 How the Algorithm Fills the Grid

1

Init side counters

k = 6, l = 13, m = 16 — starting values for right, bottom, and left borders.

Setup
2

Loop over 5×5 grid

for (let i = 1; i <= 5; i++) { for (let j = 1; j <= 5; j++) } — visit every cell.

Grid
3

Detect border side

if i == 1 top, elif j == 5 right, elif i == 5 bottom, elif j == 1 left — else inner space.

Conditionals
4

Fixed-width output

String(value).padStart(3, " ") for border digits, " " for inner cells — then console.log(line).

Format
=

Hollow border square complete

25 cells visited — O(n²) time, O(1) extra memory.

🔎 Worked Walkthrough — Key Border Cells

Trace which branch runs for representative cells in the 5×5 grid.

(i, j)BranchPrintsNotes
(1, 3)i == 13Top row uses column index
(2, 5)j == 56First right-column value (k++)
(3, 3)else (inner)Three spaces — hollow interior
(4, 1)j == 115Left column (m--)
(5, 3)i == 511Bottom row (l--)

Check order matters: top row is tested first, then right column, then bottom, then left — corners belong to the first matching branch.

Use Cases

Where this tiny pattern (and its loop structure) shows up beyond the homework prompt.

1. Teaching 2D Grids

Nested i, j loops with per-cell decisions — foundation for matrix problems.

Example: trace cell (3,3) in the walkthrough — inner branch prints spaces.

2. Fixed-Width Formatting

String(value).padStart(3, " ") keeps columns aligned when border numbers have 1 or 2 digits.

Example: compare output with and without formatting — columns drift without width 3.

3. Multiple Counters

Separate k, l, m track different sides — state management in a small program.

Example: right column starts at 6 and increments through row 4.

4. Border vs Interior

Hollow patterns print only on the boundary — compare with filled square variants.

Example: replace inner spaces with * to fill the square.

5. Complexity Intuition

Every cell visited once — makes O(n²) concrete for n×n grids.

Example: 5×5 = 25 cell checks — see the walkthrough table.

6. Input Validation Labs

Pair the pattern with Number.isFinite and minimum-size validation after parseInt(prompt()).

Example: reject n < 2 in Example 2.

Pro Tip: in grid patterns, consistent spacing matters as much as the numbers — use fixed-width formatting from the start.

Advantages

Why this pattern earns a permanent spot in beginner JavaScript courses.

  1. 1. Instant Visual Feedback

    The hollow border is instantly recognizable — numbers ring the square while the interior stays blank.

  2. 2. Real Math Connection

    Fixed-width String(value).padStart(3, " ") formatting teaches real console grid alignment — not abstract loop drill.

  3. 3. Easy to Extend

    Fill the interior with * for a solid square, or scale counter formulas for larger grids.

  4. 4. O(1) Extra Memory

    Streaming output needs no storage beyond loop counters.

Pro Tip: trace the 3×3 compact example on paper — only one inner cell to mark as spaces.

Usage Tips

Small habits that keep number-pattern code clean.

  1. 1. Init side counters first

    Set k = 6, l = 13, m = 16 before the nested loops for the 5×5 demo.

  2. 2. Validate User Input

    Avoid crashing when the user types letters instead of a number.

  3. 3. Newline After Inner Loop

    Only call console.log(line) after the inner loop finishes each row.

  4. 4. elif order matters at corners

    Check top row (i == 1) before side columns so corner cells get the right branch.

  5. 5. Dry-Run 3×3 first

    Trace the compact example on paper before coding the full 5×5 demo.

Pro Tip: if the output is a vertical list of single numbers, you almost certainly called console.log() inside the inner loop.

Common Pitfalls

Mistakes that commonly break hollow square border number pattern patterns.

  1. 1. console.log() Inside Inner Loop

    Each number lands on its own line — you get a column, not a square row.

    → Use line += String(j).padStart(3, " ") or line += " "; call console.log(line) only after the inner loop.

  2. 2. Wrong elif Order at Corners

    Checking side columns before the top/bottom row puts counter digits on corner cells.

    → Check i == 1 and i == 5 before j == 1 or j == 5 on shared rows.

  3. 3. Skipping Width-3 Formatting

    Printing bare digits without fixed width makes columns drift out of alignment.

    → Use String(value).padStart(3, " ") for border numbers and " " for inner cells.

  4. 4. Forgetting Newline After Row

    All numbers print on one long line without row breaks.

    → Call console.log(line) after the inner loop completes each row.

  5. 5. Unchecked parseInt(prompt())

    Letters or empty input yield NaN or leave n invalid.

    → Validate with Number.isFinite(n) and check n >= 2 before drawing.

Edge Cases

Check these inputs before calling the solution done.

rows = 1

Single row

Output is a single cell — for n = 1 every position is border; validate n >= 2 in user input.

rows = 0

Empty output

Outer loop never runs — print nothing or show a message.

Negative

rows < 0

Treat as invalid; re-prompt instead of silent empty output.

rows = 5

Compact trace

Center cell (3,3) is the only inner cell — good for tracing the else branch.

Bad input

Non-numeric input

Bare parseInt(prompt()) returns NaN — validate with Number.isFinite.

Large rows

Wide output

Row 9 scans 17 character positions (2×9-1) — total work grows as O(n²).

🎯 Practice Problems

Try these variations to lock in the pattern.

1. Compare with Program 58

  • Program 58 prints a diagonal mirror diamond
  • Program 59 prints a rectangular hollow border with k, l, m counters

2. Fill the interior

  • Replace inner " " with a digit or *
  • Compare hollow vs filled square output

3. Next in series

  • Continue with Program 60
  • Build on grid and border patterns

4. Scale to n = 7

  • Derive counter start values for a 7×7 border
  • Use width 4 if numbers exceed 99

Notes

  • Border checks. Top: i == 1. Right: j == n. Bottom: i == n. Left: j == 1. Else: three spaces.
  • Build one line string per row with += — call console.log(line) only after the inner loop finishes each row.
  • Validate n >= 2 for interactive programs; n = 2 has no inner cells — all border.
  • An n×n grid visits n² cells — total work grows as O(n²) for square size n.

Quick Takeaway: nested i, j loops, border if chain, counters k, l, m, width 3, then console.log(line).

⏱️ Time and Space Complexity

ProgramTimeExtra space
Nested loops (Examples 1–3)O(n²)O(1)
Digits on row i2i - 1No storage beyond loop counters
Wrap Up

🎉 Conclusion

The hollow square border number pattern is a natural follow-up to Program 58: rectangular grids with border detection and fixed-width formatting replace diagonal mirror loops. Master the fixed 5×5 version, then try user input and the compact 3×3 trace.

Practice the three examples above, then continue to Program 60 for the next pattern in the series.

Border shows numbers 1–16 clockwise on a 5×5 grid — inner cells stay blank with width-3 spacing.

💡 Best Practices

✅ Do

  • Top: if (i === 1) line += String(j).padStart(3, " ")
  • Right: else if (j === 5) line += String(k).padStart(3, " "); k++
  • Bottom: else if (i === 5) line += String(l).padStart(3, " "); l--
  • Left: else if (j === 1) line += String(m).padStart(3, " "); m--
  • Call console.log(line) after the inner loop
  • Use Number.isFinite after parseInt(prompt()) for user input

❌ Don’t

  • Skip width-3 formatting — columns drift out of alignment
  • Use wrong elif order at corners — top/bottom rows get side digits
  • Call console.log() inside the inner loop
  • Ignore bad console input in user-facing demos
  • Skip the rows = 3 dry-run before coding rows = 5

Key Takeaways

Knowledge Unlocked

Five things to remember about this hollow border square

Print the hollow border square the beginner-friendly way.

5
Core concepts
02

Left

j = rows..1

Code
03

Right

k = 2..rows

Code
04

Check

i == j or i == k

Logic
O 05

Complexity

O(n²) time

Analysis

❓ Frequently Asked Questions

A cell is on the border if i === 1, i === n, j === 1, or j === n — inner cells append three spaces.
Fixed width of 3 keeps every column aligned even when border numbers have different digit counts.
A 5×5 grid where only the boundary shows numbers 1–16 clockwise; the inside stays blank.
Program 58 prints a diagonal mirror diamond. Program 59 prints a rectangular hollow border with separate counters per side.
k tracks the right column (6..9), l the bottom row descending (13..9), m the left column descending (16..13).
Read n from input and adjust counter start values — see Example 2 for a configurable border demo.
O(n²) for an n×n grid because every cell is visited once.
Yes. Replace the inner-cell branch that appends spaces with values for the interior.
Border numbers use width 3 — inner cells need three spaces to keep columns aligned.
A 2×2 grid has no inner cells — every position is on the border.

Did you Know? 🔊

This pattern is a hollow 5×5 border: top row 1..5, right side 6..9, bottom row 13..9, left side 16..13 — inner cells are blank spaces with fixed width 3.

Continue to Program 60

Move on to the next pattern in the JavaScript number-pattern series.

Program 60 tutorial →

About the author

Mari Selvan M P
Mari Selvan M P 🔗

Developer, cloud engineer, and technical writer

  • Experience 12 years building web and cloud systems
  • Focus Full Stack Development, AWS, and Developer Education

I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

12 people found this page helpful