Monochromatic UI

← Back to skills

> "Elegance through constraint. A single hue, explored through all its tints, tones, and shades."

Category: Frontend & UI/UX
Repo: antigravity-awesome-skills
Path: skills/design-it/monochromatic-ui/SKILL.md
Updated: 6/22/2026, 9:05:36 AM

AI Summary

> "Elegance through constraint. A single hue, explored through all its tints, tones, and shades.". It is useful for React and Next.js, CSS and design systems, UI components, accessibility, and frontend polish. Source: antigravity-awesome-skills (skills/design-it/monochromatic-ui/SKILL.md).

Monochromatic UI

"Elegance through constraint. A single hue, explored through all its tints, tones, and shades."

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

  1. Single Hue: Choose one base color (e.g., deep blue). The entire UI is built using lighter (tints) and darker (shades) versions of that exact hue.
  2. High Contrast for Legibility: The darkest shade and the lightest tint must have enough contrast to pass accessibility standards when placed together.
  3. Texture over Color: Since color is restricted, use subtle textures, patterns, or varying opacities to differentiate sections.

Visual DNA

  • Colors: Monochromatic Brown or pick one dominant hue from Earth-Grounded Elegance and extrapolate it.
  • Typography: Clean and unobtrusive. The layout relies heavily on font weights to establish hierarchy since color cannot.
  • Shadows: Shadows must be tinted with the base hue, never pure black.

Web Implementation

  • Use HSL (Hue, Saturation, Lightness) heavily in CSS to make building the palette easy.
  • CSS Example:
:root {
  /* Base Hue: Deep Blue (210) */
  --mono-900: hsl(210, 80%, 10%); /* Very dark */
  --mono-700: hsl(210, 70%, 30%); /* Dark */
  --mono-500: hsl(210, 60%, 50%); /* Base */
  --mono-300: hsl(210, 50%, 80%); /* Light */
  --mono-100: hsl(210, 40%, 95%); /* Very light background */
}

body {
  background-color: var(--mono-100);
  color: var(--mono-900);
  font-family: 'Inter', sans-serif;
}

.mono-card {
  background-color: #ffffff; /* Or mono-100 */
  border: 1px solid var(--mono-300);
  border-radius: 8px;
  padding: 32px;
  /* Tinted shadow */
  box-shadow: 0 10px 25px hsla(210, 80%, 10%, 0.05);
}

.mono-btn {
  background-color: var(--mono-500);
  color: #ffffff;
  border: none;
  border-radius: 4px;
  padding: 12px 24px;
  transition: background-color 0.2s;
}

.mono-btn:hover {
  background-color: var(--mono-700);
}

.mono-subtext {
  color: var(--mono-500); /* Use mid-tones for secondary text */
  font-weight: 500;
}

App Implementation

SwiftUI

struct MonochromaticView: View {
    // Base Hue: Deep Blue (210 in 360-degree HSB/HSL)
    // In SwiftUI, hue is 0.0 to 1.0 (210/360 = 0.58)
    let mono900 = Color(hue: 0.58, saturation: 0.80, brightness: 0.10)
    let mono700 = Color(hue: 0.58, saturation: 0.70, brightness: 0.30)
    let mono500 = Color(hue: 0.58, saturation: 0.60, brightness: 0.50)
    let mono300 = Color(hue: 0.58, saturation: 0.50, brightness: 0.80)
    let mono100 = Color(hue: 0.58, saturation: 0.40, brightness: 0.95)
    
    var body: some View {
        VStack(spacing: 24) {
            // Card
            VStack(alignment: .leading, spacing: 12) {
                Text("Monochromatic Elegance")
                    .font(.title2).fontWeight(.semibold)
                    .foregroundColor(mono900)
                
                Text("Using only variations in saturation and brightness of a single hue.")
                    .foregroundColor(mono500)
            }
            .padding(32)
            .background(Color.white)
            .border(mono300, width: 1)
            .shadow(color: mono900.opacity(0.1), radius: 15, y: 5) // Tinted shadow
            
            // Button
            Button(action: {}) {
                Text("Primary Action")
                    .fontWeight(.bold)
                    .foregroundColor(.white)
                    .frame(maxWidth: .infinity)
                    .padding()
                    .background(mono500)
                    .cornerRadius(8)
            }
        }
        .padding()
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .background(mono100)
    }
}
  • Define your colors using Color(hue: saturation: brightness:). This ensures math-perfect monochromatic harmony.
  • Always tint your drop shadows with your mono900 color. Pure black shadows look dirty in a strict monochromatic UI.

Flutter

class MonochromaticScreen extends StatelessWidget {
  // Base Hue: Deep Blue (210)
  // Flutter HSVColor uses Hue 0-360, Saturation 0.0-1.0, Value 0.0-1.0
  final Color mono900 = const HSVColor.fromAHSV(1.0, 210, 0.80, 0.10).toColor();
  final Color mono500 = const HSVColor.fromAHSV(1.0, 210, 0.60, 0.50).toColor();
  final Color mono300 = const HSVColor.fromAHSV(1.0, 210, 0.50, 0.80).toColor();
  final Color mono100 = const HSVColor.fromAHSV(1.0, 210, 0.40, 0.95).toColor();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: mono100,
      body: Center(
        child: Padding(
          padding: const EdgeInsets.all(24.0),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              // Card
              Container(
                width: double.infinity,
                padding: const EdgeInsets.all(32),
                decoration: BoxDecoration(
                  color: Colors.white,
                  border: Border.all(color: mono300),
                  borderRadius: BorderRadius.circular(8),
                  boxShadow: [
                    BoxShadow(color: mono900.withOpacity(0.1), blurRadius: 15, offset: const Offset(0, 5))
                  ],
                ),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text('Monochromatic', style: TextStyle(fontSize: 24, fontWeight: FontWeight.w600, color: mono900)),
                    const SizedBox(height: 12),
                    Text('Variations of a single hue.', style: TextStyle(fontSize: 16, color: mono500)),
                  ],
                ),
              ),
              const SizedBox(height: 24),
              // Button
              ElevatedButton(
                onPressed: () {},
                style: ElevatedButton.styleFrom(
                  backgroundColor: mono500,
                  foregroundColor: Colors.white,
                  minimumSize: const Size(double.infinity, 56),
                  shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
                  elevation: 0,
                ),
                child: const Text('Primary Action', style: TextStyle(fontWeight: FontWeight.bold)),
              ),
            ],
          ),
        ),
      ),
    );
  }
}
  • Flutter's HSVColor.fromAHSV() is the best way to explicitly code a monochromatic palette without guessing hex codes.

React Native

// Base Hue: Deep Blue (210)
const theme = {
  mono900: 'hsl(210, 80%, 10%)',
  mono700: 'hsl(210, 70%, 30%)',
  mono500: 'hsl(210, 60%, 50%)',
  mono300: 'hsl(210, 50%, 80%)',
  mono100: 'hsl(210, 40%, 95%)',
};

const MonochromaticScreen = () => {
  return (
    <View style={{ flex: 1, backgroundColor: theme.mono100, padding: 24, justifyContent: 'center' }}>
      
      <View style={{
        backgroundColor: '#FFFFFF',
        borderColor: theme.mono300,
        borderWidth: 1,
        borderRadius: 8,
        padding: 32,
        marginBottom: 24,
        // Tinted shadow (iOS)
        shadowColor: theme.mono900, shadowOffset: { width: 0, height: 5 },
        shadowOpacity: 0.1, shadowRadius: 15,
      }}>
        <Text style={{ fontSize: 24, fontWeight: '600', color: theme.mono900, marginBottom: 12 }}>
          Monochromatic
        </Text>
        <Text style={{ fontSize: 16, color: theme.mono500 }}>
          Using HSL strings in React Native makes palette generation trivial.
        </Text>
      </View>

      <TouchableOpacity style={{
        backgroundColor: theme.mono500,
        padding: 16,
        borderRadius: 8,
        alignItems: 'center'
      }}>
        <Text style={{ fontWeight: 'bold', color: '#FFFFFF', fontSize: 16 }}>
          Primary Action
        </Text>
      </TouchableOpacity>
      
    </View>
  );
};
  • React Native's StyleSheet accepts CSS hsl() strings natively. Use them! It makes debugging and tweaking a monochromatic palette a million times easier than using hex codes.

Jetpack Compose

@Composable
fun MonochromaticScreen() {
    // Base Hue: Deep Blue (210)
    // Compose Color.hsv requires Hue 0-360f, Saturation 0-1f, Value 0-1f
    val mono900 = Color.hsv(210f, 0.80f, 0.10f)
    val mono500 = Color.hsv(210f, 0.60f, 0.50f)
    val mono300 = Color.hsv(210f, 0.50f, 0.80f)
    val mono100 = Color.hsv(210f, 0.40f, 0.95f)

    Column(
        modifier = Modifier
            .fillMaxSize()
            .background(mono100)
            .padding(24.dp),
        verticalArrangement = Arrangement.Center
    ) {
        // Card
        Box(
            modifier = Modifier
                .fillMaxWidth()
                .shadow(15.dp, RoundedCornerShape(8.dp), spotColor = mono900.copy(alpha = 0.2f))
                .background(Color.White, RoundedCornerShape(8.dp))
                .border(1.dp, mono300, RoundedCornerShape(8.dp))
                .padding(32.dp)
        ) {
            Column {
                Text("Monochromatic", fontSize = 24.sp, fontWeight = FontWeight.SemiBold, color = mono900)
                Spacer(Modifier.height(12.dp))
                Text("Strictly enforced hue discipline.", color = mono500)
            }
        }
        
        Spacer(Modifier.height(24.dp))
        
        // Button
        Button(
            onClick = { },
            colors = ButtonDefaults.buttonColors(containerColor = mono500, contentColor = Color.White),
            shape = RoundedCornerShape(8.dp),
            modifier = Modifier.fillMaxWidth().height(56.dp)
        ) {
            Text("Primary Action", fontWeight = FontWeight.Bold)
        }
    }
}
  • Use Color.hsv() to define the palette.
  • Set the spotColor in your Modifier.shadow to mono900 to keep the shadows from looking muddy or disjointed from the design system.

Do's and Don'ts

  • DO: Use pure white or pure black as absolute extremes if needed for text legibility.
  • DON'T: Sneak in an accent color. If you add a red error button to a blue monochromatic UI, it immediately breaks the aesthetic and becomes "duotone" or standard UI. Find a way to signify errors using bold text or dark shades of the base hue.

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.

Related skills