This dashboard examines Australia’s progress towards Closing the Gap Target 3 – achieving 95% Aboriginal and Torres Strait Islander children enrolled in early childhood education by 2025. From 61.3% in 2016 to 94.2% in 2024, Australia has demonstrated remarkable progress and is well-positioned to achieve universal access within the target timeframe.
Indigenous ECE enrolment is 94.2% (2024), up from 61.3% in 2016. Only 0.8 pp short of the 95% target.
Data sources
Productivity Commission. (2025).
Closing the Gap – Outcome Area 3: Early childhood education.
View
source
RIFIC. (2025). Target 3 data platform.
View
source
---
title: "Closing the Gap – Early Childhood Education (Target 3)"
subtitle: "Australia’s progress towards universal access by 2025"
author: "Hannah Samson (S4116329)"
output:
flexdashboard::flex_dashboard:
orientation: rows
vertical_layout: fill
theme: flatly
social: menu
source_code: embed
---
<style>
@import url('https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;600;700&display=swap');
/* Base */
body{font-family:'Open Sans',Arial,sans-serif;font-size:14px;color:#212529;line-height:1.5}
.navbar-inverse{background-color:#5126ab !important;border-color:#5126ab !important;min-height:46px}
.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav > li > a{color:#fff !important}
/* Remove grey auto H3 headings; keep our purple headers */
.section.level3 > h3{display:none !important}
/* Purple section headers + compact cards */
.section-title{background:#5126ab;color:#fff;padding:8px 16px;margin:0 0 6px 0;border-radius:6px 6px 0 0;font-size:12px;font-weight:600;text-transform:uppercase}
.chart-box{background:#fff;border:1px solid #dee2e6;border-radius:0 0 6px 6px;padding:8px;height:100%}
/* Intro panel compact */
.intro-panel{background:#fafafa;border:1px solid #dee2e6;border-left:4px solid #5126ab;padding:12px 14px;border-radius:6px;margin-bottom:6px}
/* Value boxes (4 across) */
.value-box{border:2px solid #5126ab;border-radius:6px;background:#fff !important}
.value-box .value{font-size:28px;font-weight:600;color:#5126ab !important}
.value-box .caption{font-size:11px;font-weight:500;text-transform:uppercase;color:#5126ab !important}
/* Optional centre divider for the 2×2 area */
.split-left{padding-right:10px;border-right:1px solid #eee}
.split-right{padding-left:10px}
.insights-box h4 {
font-size: 11px; /* smaller than current 12px */
font-weight: 600;
margin: 4px 0;
color: #5126ab;
text-transform: uppercase;
}
</style>
```{r setup, include=FALSE}
knitr::opts_chunk$set(message=FALSE, warning=FALSE, echo=FALSE, fig.width=8, fig.height=3.2)
library(tidyverse)
library(readr)
library(scales)
library(plotly)
library(flexdashboard)
library(htmltools)
pal <- list(
primary = "#5126ab",
success = "#28a745",
warning = "#ffc107",
info = "#17a2b8",
danger = "#dc3545",
neutral = "#6c757d"
)
```
```{r data_processing, include=FALSE}
# Load CSV (ensure file exists in project)
df_raw <- read_csv("ctg-202507-ctg03-childhood-education-dataset.csv",
locale = locale(encoding = "latin1"))
# Tidy data
actual_data <- df_raw %>%
filter(Description2 == "Actual",
Description3 == "Proportion",
Unit == "%",
Indigenous_Status %in% c("Aboriginal and Torres Strait Islander people","Non-Indigenous people")) %>%
select(Year, Indigenous_Status, NSW:Aust) %>%
mutate(Year = suppressWarnings(as.numeric(Year))) %>%
filter(!is.na(Year)) %>%
pivot_longer(NSW:Aust, names_to = "jurisdiction", values_to = "rate_text") %>%
mutate(rate = as.numeric(str_replace_all(rate_text, "[^0-9.]", ""))) %>%
filter(!is.na(rate)) %>%
mutate(rate = rate/100) %>%
select(Year, Indigenous_Status, jurisdiction, rate)
# Metrics
target_rate <- 0.95
latest_national <- actual_data %>%
filter(jurisdiction == "Aust",
Indigenous_Status == "Aboriginal and Torres Strait Islander people") %>%
arrange(desc(Year)) %>%
slice(1)
current_rate <- latest_national$rate
current_year <- latest_national$Year
baseline_data <- actual_data %>%
filter(jurisdiction == "Aust",
Indigenous_Status == "Aboriginal and Torres Strait Islander people",
Year == min(Year, na.rm = TRUE))
baseline_rate <- baseline_data$rate[1]
baseline_year <- baseline_data$Year[1]
current_pct <- round(current_rate*100, 1)
gap_to_target <- round((target_rate - current_rate)*100, 1)
improvement <- round((current_rate - baseline_rate)*100, 1)
years_left <- 2025 - current_year
# National series
national_trends <- actual_data %>%
filter(jurisdiction == "Aust") %>%
mutate(population = if_else(Indigenous_Status == "Aboriginal and Torres Strait Islander people","Indigenous","Non-Indigenous")) %>%
select(Year, population, rate)
# Latest state year
latest_year_states <- actual_data %>%
filter(jurisdiction != "Aust") %>%
summarize(y = max(Year, na.rm = TRUE)) %>% pull(y)
# State performance (Indigenous)
state_performance <- actual_data %>%
filter(Year == latest_year_states,
jurisdiction != "Aust",
Indigenous_Status == "Aboriginal and Torres Strait Islander people") %>%
mutate(
state_name = case_when(
jurisdiction == "NSW" ~ "New South Wales",
jurisdiction == "Vic" ~ "Victoria",
jurisdiction == "Qld" ~ "Queensland",
jurisdiction == "WA" ~ "Western Australia",
jurisdiction == "SA" ~ "South Australia",
jurisdiction == "Tas" ~ "Tasmania",
jurisdiction == "ACT" ~ "Australian Capital Territory",
jurisdiction == "NT" ~ "Northern Territory"
),
performance = case_when(
rate >= target_rate ~ "Exceeds target",
rate >= 0.90 ~ "Close to target",
TRUE ~ "Needs support"
)
) %>%
arrange(rate) %>%
mutate(state_name = factor(state_name, levels = state_name))
# Equity (Indigenous vs Non‑Indigenous)
equity_data <- actual_data %>%
filter(Year == latest_year_states, jurisdiction != "Aust") %>%
select(jurisdiction, Indigenous_Status, rate) %>%
pivot_wider(names_from = Indigenous_Status, values_from = rate) %>%
mutate(
gap_pp = (`Aboriginal and Torres Strait Islander people` - `Non-Indigenous people`) * 100,
state_name = case_when(
jurisdiction == "NSW" ~ "New South Wales",
jurisdiction == "Vic" ~ "Victoria",
jurisdiction == "Qld" ~ "Queensland",
jurisdiction == "WA" ~ "Western Australia",
jurisdiction == "SA" ~ "South Australia",
jurisdiction == "Tas" ~ "Tasmania",
jurisdiction == "ACT" ~ "Australian Capital Territory",
jurisdiction == "NT" ~ "Northern Territory"
),
gap_status = case_when(
gap_pp >= 0 ~ "Indigenous ≥ Non-Indigenous",
gap_pp >= -5 ~ "Small gap",
TRUE ~ "Large gap"
)
) %>%
arrange(gap_pp) %>%
mutate(state_name = factor(state_name, levels = state_name))
exceeds_count <- sum(state_performance$performance == "Exceeds target", na.rm = TRUE)
equity_count <- sum(equity_data$gap_status == "Indigenous ≥ Non-Indigenous", na.rm = TRUE)
```
Row {data-height=40}
-----------------------------------------------------------------------
<div class="intro-panel">
This dashboard examines Australia's progress towards <strong>Closing the Gap Target 3</strong> – achieving 95% Aboriginal and Torres Strait Islander children enrolled in early childhood education by 2025. From <strong>`r round(baseline_rate*100,1)`%</strong> in `r baseline_year` to <strong>`r current_pct`%</strong> in `r current_year`, Australia has demonstrated remarkable progress and is well-positioned to achieve universal access within the target timeframe.
</div>
Row {data-height=40}
-----------------------------------------------------------------------
### Current Enrolment {.value-box}
```{r}
valueBox(
value = paste0(current_pct, "%"),
caption = paste0("Indigenous ECE Enrolment (", current_year, ")"),
icon = "fa-graduation-cap"
)
```
### Gap to Target {.value-box}
```{r}
valueBox(
value = paste0(gap_to_target, " pp"),
caption = "Gap to 95% Target",
icon = "fa-bullseye"
)
```
### Total Progress {.value-box}
```{r}
valueBox(
value = paste0("+", improvement, " pp"),
caption = paste0("Improvement Since ", baseline_year),
icon = "fa-arrow-up"
)
```
### Time Remaining {.value-box}
```{r}
valueBox(
value = paste0(years_left, " year", if(years_left != 1) "s" else ""),
caption = "Until 2025 Target",
icon = "fa-calendar"
)
```
Row {data-height=180}
-----------------------------------------------------------------------
###
<div class="section-title">National Enrolment Trends: Journey to Universal Access</div>
<div class="chart-box">
```{r}
p1 <- national_trends %>%
ggplot(aes(Year, rate, colour = population)) +
geom_hline(yintercept = target_rate, linetype = "dashed",
colour = pal$danger, linewidth = 1.2) +
geom_line(linewidth = 1.5) +
geom_point(size = 2.5) +
scale_colour_manual(
values = c("Indigenous" = pal$primary, "Non-Indigenous" = pal$neutral),
name = "Population"
) +
scale_y_continuous(
labels = percent_format(accuracy = 1),
limits = c(0.55, 1.05),
breaks = seq(0.6, 1.0, 0.1)
) +
scale_x_continuous(breaks = pretty_breaks(6)) +
labs(
title = "Early Childhood Education Enrolment Rates",
subtitle = "Dashed line shows 95% target",
x = "Year",
y = "Enrolment Rate"
) +
theme_minimal(base_size = 11) +
theme(
legend.position = "bottom",
legend.title = element_blank(),
panel.grid.minor = element_blank(),
plot.title = element_text(size = 12, face = "bold", colour = pal$primary),
plot.subtitle = element_text(size = 10, colour = pal$neutral)
)
ggplotly(p1, tooltip = c("x", "y", "colour"))
```
</div>
###
<div class="section-title">Performance by Jurisdiction: Success Stories and Priorities</div>
<div class="chart-box">
```{r}
p2 <- state_performance %>%
mutate(rate_pct = scales::percent(rate, accuracy = 0.1)) %>%
ggplot(aes(
x = reorder(state_name, rate),
y = rate,
fill = performance,
text = paste0(
"Jurisdiction: ", state_name,
"<br>Enrolment: ", rate_pct,
"<br>Performance: ", performance
)
)) +
geom_col(width = 0.7) +
geom_hline(yintercept = target_rate, linetype = "dashed",
colour = pal$danger, linewidth = 1.2) +
coord_flip() +
scale_y_continuous(labels = percent_format(accuracy = 1),
limits = c(0, 1.1), expand = c(0, 0)) +
scale_fill_manual(values = c(
"Exceeds target" = pal$success,
"Close to target" = pal$info,
"Needs support" = pal$warning
), name = "Performance") +
labs(
title = paste0("Indigenous ECE Enrolment by Jurisdiction (", latest_year_states, ")"),
subtitle = "Dashed line shows 95% target",
x = NULL, y = "Enrolment Rate"
) +
theme_minimal(base_size = 11) +
theme(
legend.position = "bottom",
legend.title = element_blank(),
panel.grid.major.y = element_blank(),
panel.grid.minor = element_blank(),
plot.title = element_text(size = 12, face = "bold", colour = pal$primary),
plot.subtitle = element_text(size = 10, colour = pal$neutral)
)
ggplotly(p2, tooltip = "text") %>%
layout(margin = list(t = 0, r = 10, b = 40, l = 60))
```
</div>
Row {data-height=180}
-----------------------------------------------------------------------
###
<div class="section-title">Indigenous vs Non-Indigenous Enrolment Comparison</div>
<div class="chart-box">
```{r}
p3 <- equity_data %>%
ggplot(aes(
reorder(state_name, gap_pp),
gap_pp,
fill = gap_status,
text = paste0(
"State: ", state_name,
"<br>Gap: ", round(gap_pp, 1), " pp",
"<br>Status: ", gap_status
)
)) +
geom_hline(yintercept = 0, colour = pal$neutral, linewidth = 1.2) +
geom_col(width = 0.7) +
coord_flip() +
scale_fill_manual(
values = c(
"Indigenous ≥ Non-Indigenous" = pal$success,
"Small gap" = pal$info,
"Large gap" = pal$warning
),
name = "Equity Status"
) +
labs(
title = paste0("Enrolment Gap Analysis (", latest_year_states, ")"),
subtitle = "Positive values show Indigenous rates exceed Non-Indigenous",
x = NULL,
y = "Percentage Points (Indigenous − Non-Indigenous)"
) +
theme_minimal(base_size = 11) +
theme(
legend.position = "bottom",
panel.grid.major.y = element_blank(),
panel.grid.minor = element_blank(),
plot.title = element_text(size = 12, face = "bold", colour = pal$primary),
plot.subtitle = element_text(size = 10, colour = pal$neutral)
)
ggplotly(p3, tooltip = "text")
```
</div>
###
<div class="section-title">Key Insights & Priorities</div>
<div class="insights-box">
<h4>Status</h4>
Indigenous ECE enrolment is <span class="highlight">`r current_pct`%</span> (`r current_year`), up from <span class="highlight">`r round(baseline_rate*100,1)`%</span> in `r baseline_year`. Only <span class="highlight">`r gap_to_target` pp</span> short of the 95% target.
<h4>Highlights</h4>
<ul>
<li><strong>Growth:</strong> Steady increases across years</li>
<li><strong>Leaders:</strong> `r exceeds_count` states already ≥95%</li>
<li><strong>Equity:</strong> `r equity_count` states show parity with non-Indigenous</li>
</ul>
<h4>Priorities</h4>
<ul>
<li>Remote NT support</li>
<li>Urban access in ACT</li>
<li>Regional scale-up in NSW</li>
<li>Share lessons from high performers</li>
</ul>
<div class="references">
<strong>Data sources</strong><br>
Productivity Commission. (2025). Closing the Gap – Outcome Area 3: Early childhood education.
<a href="https://www.pc.gov.au/closing-the-gap-data/dashboard/se/outcome-area3" target="_blank">View source</a><br>
RIFIC. (2025). Target 3 data platform.
<a href="https://www.rific.gov.au/closing-the-gap?app=rific&code=ctg&release=r3&latitude=-24&longitude=134®ion=Target3_AUS" target="_blank">View source</a>