Design data-dense UI components with clarity and precision
Design-style skill for Data-Dense Design: tight margins, monospace tabular data, and minimal decoration for expert users.
Maintainer of this project? Claim this page to edit the listing.
13.6.1Add to Favorites
Why it matters
Help developers and designers create information-rich interfaces that display complex datasets, tables, charts, and dashboards with optimal readability, hierarchy, and user comprehension while maintaining visual clarity and avoiding cognitive overload.
Outcomes
What it gets done
Structure dense tabular data with appropriate column hierarchies, sorting, and filtering patterns
Design dashboard layouts that balance multiple metrics, charts, and KPIs without overwhelming users
Apply typography, spacing, and color systems that enhance scanability of numeric and text-heavy content
Implement progressive disclosure patterns to reveal detail layers without cluttering the primary view
Install
Add it to your toolbox
Run in your project directory:
curl -fsSL https://spark.entire.vc/get/ag-data-dense-design | bash Overview
Data-Dense Design
A design-style skill for Data-Dense Design - tight margins, monospace tabular alignment, and minimal decoration for expert users - with matching Web CSS and SwiftUI implementations. Use it for trading terminals, admin dashboards, IDEs, or monitoring consoles built for power users who prioritize scanning speed and density over generous whitespace.
What it does
Data-Dense Design is a design-style child skill ('density is a feature - for expert users, reducing clicks is more important than whitespace'), part of the design-it family and not meant to be triggered directly. Three core principles: Compact Layouts (extremely tight margins and padding, often 2px to 4px), Monospace & Tabular Data (numbers must align vertically perfectly), and High Utility (every pixel serves a functional purpose, with minimal purely decorative elements).
When to use - and when NOT to
Use it when the user's request matches an expert-tool, high-information-throughput aesthetic - trading terminals, admin dashboards, IDEs, or monitoring consoles built for power users who prioritize scanning speed over visual breathing room. As a design sub-style, it's selected by the parent design-it skill's routing rather than invoked on its own.
Inputs and outputs
Visual DNA leans on Industrial Chic or Minimalist Slate high-contrast palettes, avoiding bright backgrounds - dark themes are heavily preferred to reduce eye strain over long 8-hour sessions. Typography stays small (11px-13px base sizes) with strict monospace fonts (Fira Code, JetBrains Mono) for any actual data, and thin 1px borders (#333 or #e0e0e0) separate tiny data cells extensively. The web implementation uses an IDE-dark background (#1e1e1e), a compact toolbar with 2px/4px padding, and a dense data table with monospace numeric cells right-aligned for visual scanning, zebra-striped rows (nth-child(even)), and a strong hover-row highlight color for row-level selection feedback in a data grid.
.data-table th, .data-table td {
padding: 4px 8px;
border: 1px solid #3c3c3c;
text-align: right;
}
.data-table tr:hover { background-color: #094771; color: #fff; }
Integrations
SwiftUI reproduces the trading-terminal look with a zero-spacing Grid inside a bidirectionally-scrolling ScrollView, header cells in bold 11pt monospaced font and data rows showing ticker/bid/ask/change values with color-coded positive/negative changes - the same right-aligned, monospace-numeric, high-density table structure as the web version, against a dark Color(white: 0.12) background. Positive changes render in green and negative changes in red, letting a user parse market direction from a glance without reading the actual numbers - a functional color choice rather than decoration, consistent with the style's high-utility principle.
Who it's for
Designers and developers building expert tools - trading terminals, admin panels, IDEs, monitoring dashboards - where power users need to scan large amounts of tabular data quickly and prioritize information density and click-reduction over generous whitespace - a deliberate rejection of the airy, whitespace-heavy defaults that suit casual consumer apps but slow down a user who lives in the interface for hours a day.
Source README
Data-Dense Design
"Density is a feature. For expert users, reducing clicks is more important than whitespace."
When to Use
Use this sub-style when the user's request matches the aesthetic described above. This is a child reference of the design-it skill and is not meant to be triggered directly.
Core Principles
- Compact Layouts: Extremely tight margins and padding (often 2px to 4px).
- Monospace & Tabular Data: Numbers must align vertically perfectly.
- High Utility: Every pixel serves a functional purpose. Minimal purely decorative elements.
Visual DNA
- Colors: Industrial Chic (high contrast) or Minimalist Slate. Avoid bright backgrounds. Dark themes are heavily preferred to reduce eye strain over 8-hour sessions.
- Typography: Small base sizes (
11px-13px). Strict use of monospace fonts (Fira Code,JetBrains Mono) for data. - Borders: Thin
1pxborders (#333or#e0e0e0) are used extensively to separate tiny cells of data.
Web Implementation
- Tables, CSS Grid, and Flexbox with zero gap.
- CSS Example:
body {
background-color: #1e1e1e; /* IDE Dark */
color: #cccccc;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
font-size: 12px; /* Very small */
margin: 0;
}
.dense-toolbar {
display: flex;
background-color: #2d2d2d;
border-bottom: 1px solid #3c3c3c;
padding: 2px 4px;
}
.dense-btn {
background: transparent;
color: #ccc;
border: 1px solid transparent;
padding: 2px 8px;
border-radius: 2px;
cursor: pointer;
}
.dense-btn:hover {
background-color: #3c3c3c;
border-color: #555;
}
/* Dense Data Table */
.data-table {
width: 100%;
border-collapse: collapse;
font-family: 'JetBrains Mono', monospace;
}
.data-table th, .data-table td {
padding: 4px 8px;
border: 1px solid #3c3c3c;
text-align: right; /* Numbers align right */
}
.data-table tr:nth-child(even) { background-color: #252526; }
.data-table tr:hover { background-color: #094771; color: #fff; } /* Selection highlight */
App Implementation
SwiftUI
struct DataDenseView: View {
var body: some View {
ScrollView([.horizontal, .vertical]) {
Grid(horizontalSpacing: 0, verticalSpacing: 0) {
// Header Row
GridRow {
HeaderCell("SYM")
HeaderCell("BID")
HeaderCell("ASK")
HeaderCell("CHG")
}
// Data Rows
DataRow(sym: "AAPL", bid: "173.40", ask: "173.45", chg: "+0.12", isPos: true)
DataRow(sym: "MSFT", bid: "320.10", ask: "320.15", chg: "-0.45", isPos: false)
DataRow(sym: "GOOG", bid: "135.20", ask: "135.30", chg: "+0.02", isPos: true)
}
.border(Color.gray.opacity(0.3), width: 1)
}
.background(Color(white: 0.12)) // Dark IDE background
}
}
struct HeaderCell: View {
let text: String
init(_ text: String) { self.text = text }
var body: some View {
Text(text)
.font(.system(size: 11, weight: .bold, design: .monospaced))
.foregroundColor(.gray)
.padding(4)
.frame(minWidth: 60, alignment: .leading)
.border(Color.gray.opacity(0.3), width: 0.5)
.background(Color(white: 0.18))
}
}
struct DataRow: View {
let sym, bid, ask, chg: String
let isPos: Bool
var body: some View {
GridRow {
Cell(sym, color: .white)
Cell(bid, color: .white, align: .trailing)
Cell(ask, color: .white, align: .trailing)
Cell(chg, color: isPos ? .green : .red, align: .trailing)
}
}
}
struct Cell: View {
let text: String
let color: Color
let align: Alignment
init(_ text: String, color: Color, align: Alignment = .leading) {
self.text = text; self.color = color; self.align = align
}
var body: some View {
Text(text)
.font(.system(size: 12, design: .monospaced))
.foregroundColor(color)
.padding(4)
.frame(minWidth: 60, alignment: align)
.border(Color.gray.opacity(0.3), width: 0.5)
}
}
- Use
Gridwith0spacing. - Font must be
.system(..., design: .monospaced). - Use a
.border()with0.5width on every single cell to recreate the dense spreadsheet look.
Flutter
class DataDenseScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFF1E1E1E),
body: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Theme(
// Override theme specifically to make the table hyper-dense
data: Theme.of(context).copyWith(
dividerColor: Colors.grey[800],
),
child: DataTable(
headingRowHeight: 28, // Extremely dense
dataRowMinHeight: 24,
dataRowMaxHeight: 24, // Extremely dense
columnSpacing: 16,
border: TableBorder.all(color: Colors.grey[800]!, width: 1),
columns: const [
DataColumn(label: Text('SYM', style: TextStyle(color: Colors.grey, fontSize: 11, fontFamily: 'RobotoMono'))),
DataColumn(label: Text('BID', style: TextStyle(color: Colors.grey, fontSize: 11, fontFamily: 'RobotoMono')), numeric: true),
DataColumn(label: Text('ASK', style: TextStyle(color: Colors.grey, fontSize: 11, fontFamily: 'RobotoMono')), numeric: true),
],
rows: [
_buildRow('AAPL', '173.40', '173.45'),
_buildRow('MSFT', '320.10', '320.15'),
_buildRow('GOOG', '135.20', '135.30'),
],
),
),
),
),
);
}
DataRow _buildRow(String sym, String bid, String ask) {
const style = TextStyle(color: Colors.white, fontSize: 12, fontFamily: 'RobotoMono');
return DataRow(
cells: [
DataCell(Text(sym, style: style)),
DataCell(Text(bid, style: style)),
DataCell(Text(ask, style: style)),
],
);
}
}
- Flutter's
DataTableis perfect, but you must manually crush theheadingRowHeightanddataRowHeightdown from their Material defaults (which are huge). - Wrap in dual
SingleChildScrollViewto allow panning around large data sets.
React Native
const DataDenseScreen = () => {
return (
<ScrollView style={{ backgroundColor: '#1E1E1E', flex: 1 }}>
<ScrollView horizontal>
<View style={{ borderWidth: 1, borderColor: '#333' }}>
{/* Header */}
<View style={{ flexDirection: 'row', backgroundColor: '#2D2D2D' }}>
<HeaderCell text="SYM" width={60} />
<HeaderCell text="BID" width={80} align="right" />
<HeaderCell text="ASK" width={80} align="right" />
<HeaderCell text="CHG" width={60} align="right" />
</View>
{/* Rows */}
<DataRow sym="AAPL" bid="173.40" ask="173.45" chg="+0.12" isPos={true} />
<DataRow sym="MSFT" bid="320.10" ask="320.15" chg="-0.45" isPos={false} />
</View>
</ScrollView>
</ScrollView>
);
};
const HeaderCell = ({ text, width, align = 'left' }) => (
<View style={{ width, padding: 4, borderWidth: 0.5, borderColor: '#333' }}>
<Text style={{ color: '#999', fontSize: 11, fontFamily: 'monospace', textAlign: align, fontWeight: 'bold' }}>
{text}
</Text>
</View>
);
const DataRow = ({ sym, bid, ask, chg, isPos }) => (
<View style={{ flexDirection: 'row' }}>
<Cell text={sym} width={60} />
<Cell text={bid} width={80} align="right" />
<Cell text={ask} width={80} align="right" />
<Cell text={chg} width={60} align="right" color={isPos ? '#4CAF50' : '#F44336'} />
</View>
);
const Cell = ({ text, width, align = 'left', color = '#CCC' }) => (
<View style={{ width, padding: 4, borderWidth: 0.5, borderColor: '#333' }}>
<Text style={{ color, fontSize: 12, fontFamily: 'monospace', textAlign: align }}>
{text}
</Text>
</View>
);
- React Native doesn't have a native Table component, so you must construct a grid using
flexDirection: 'row'and strictwidthproperties on cells. - Double scroll views (one vertical, one horizontal inside it) are standard for mobile data tables.
Jetpack Compose
@Composable
fun DataDenseScreen() {
val scrollStateHorizontal = rememberScrollState()
val scrollStateVertical = rememberScrollState()
Box(
modifier = Modifier
.fillMaxSize()
.background(Color(0xFF1E1E1E))
.verticalScroll(scrollStateVertical)
.horizontalScroll(scrollStateHorizontal)
.padding(8.dp)
) {
Column(modifier = Modifier.border(1.dp, Color(0xFF333333))) {
// Header
Row(modifier = Modifier.background(Color(0xFF2D2D2D))) {
Cell("SYM", 60.dp, Color.Gray, true)
Cell("BID", 80.dp, Color.Gray, true, TextAlign.End)
Cell("ASK", 80.dp, Color.Gray, true, TextAlign.End)
}
// Rows
DataRow("AAPL", "173.40", "173.45")
DataRow("MSFT", "320.10", "320.15")
}
}
}
@Composable
fun DataRow(sym: String, bid: String, ask: String) {
Row {
Cell(sym, 60.dp, Color.White, false)
Cell(bid, 80.dp, Color.White, false, TextAlign.End)
Cell(ask, 80.dp, Color.White, false, TextAlign.End)
}
}
@Composable
fun Cell(text: String, width: Dp, color: Color, isHeader: Boolean, align: TextAlign = TextAlign.Start) {
Text(
text = text,
color = color,
fontSize = if (isHeader) 11.sp else 12.sp,
fontWeight = if (isHeader) FontWeight.Bold else FontWeight.Normal,
fontFamily = FontFamily.Monospace,
textAlign = align,
modifier = Modifier
.width(width)
.border(0.5.dp, Color(0xFF333333))
.padding(4.dp)
)
}
- Chain
.verticalScroll()and.horizontalScroll()on the rootBox. - Compose allows
.border()directly onTextmodifiers, making spreadsheet grids very clean to implement without wrapping everything inBoxes.
Do's and Don'ts
- DO: Use color coding (red/green) for data deltas, but keep the saturation muted to prevent eye fatigue.
- DON'T: Use large padding or giant H1 headers. Expert users already know what screen they are on.
Limitations
- This is a styling reference and does not replace environment-specific validation, accessibility testing, or expert review.
- Ensure appropriate contrast ratios and responsive behaviors are verified separately.
FAQ
Common questions
Discussion
Questions & comments · 0
Sign In Sign in to leave a comment.