Skip to content
CMO & CTO
CMO & CTO

Closing the Bridge Between Marketing and Technology, By Luis Fernandez

  • Digital Experience
    • Experience Strategy
    • Experience-Driven Commerce
    • Multi-Channel Experience
    • Personalization & Targeting
    • SEO & Performance
    • User Journey & Behavior
  • Marketing Technologies
    • Analytics & Measurement
    • Content Management Systems
    • Customer Data Platforms
    • Digital Asset Management
    • Marketing Automation
    • MarTech Stack & Strategy
    • Technology Buying & ROI
  • Software Engineering
    • Software Engineering
    • Software Architecture
    • General Software
    • Development Practices
    • Productivity & Workflow
    • Code
    • Engineering Management
    • Business of Software
    • Code
    • Digital Transformation
    • Systems Thinking
    • Technical Implementation
  • About
CMO & CTO

Closing the Bridge Between Marketing and Technology, By Luis Fernandez

Accessibility in Desktop Java: Contrast, Fonts, Inputs

Posted on September 9, 2011 By Luis Fernandez

Accessibility in Desktop Java

Now that Java 7 is out and Nimbus is not the new kid anymore, I keep running into the same question from teams that ship Swing apps for regular folks in offices and call centers. How do we make this thing friendly for people who do not live on twenty seven inch displays, or who rely on readers and keyboard first flows. Today feels like the right day to write down what works for me with Accessibility in Desktop Java, with a focus on contrast, fonts, and inputs, and a few thoughts on Look and Feel choices across Windows, Mac, and Linux. If you build line of business tools or admin consoles, this is for you.

Definitions that keep the team aligned

Accessibility in desktop Java means your UI can be used by more people without hacks. That covers screen readers through the Java Access Bridge on Windows, VoiceOver on Mac, and the GNOME stack on Linux. It also covers people who want larger text, need good keyboard navigation, and need sensible contrast.

Contrast is about text and icons against their background. If the ratio is weak, people squint, miss errors, or give up. WCAG 2.0 talks about 4.5 to 1 for normal text as a decent baseline.

Fonts are not just style. They are speed. Bigger and crisper fonts reduce mistakes and reduce support tickets. In Swing, that means setting default fonts through UIManager and respecting system hints like antialiasing.

Inputs means both mouse and keyboard. Every action you can click should have a key. Every focusable thing should have a clear focus ring. Mnemonics and accelerators save wrists.

Look and Feel is the skin and behavior of your app. Nimbus is pretty and consistent. The system look and feel blends with the host. Both can be accessible if you do your part.

Examples that ship well

Set a sane default font across the app. Do this early in startup, before creating components. Scale by DPI and keep it consistent.

import javax.swing.*;
import javax.swing.plaf.FontUIResource;
import java.awt.*;
import java.util.Enumeration;

public final class Fonts {
  public static void applyUIFont(float baseSize) {
    float dpi = Toolkit.getDefaultToolkit().getScreenResolution();
    float size = Math.round(baseSize * (dpi / 96f)); // 96 as a friendly baseline
    FontUIResource uiFont = new FontUIResource("Segoe UI", Font.PLAIN, (int) size);
    Enumeration keys = UIManager.getDefaults().keys();
    while (keys.hasMoreElements()) {
      Object key = keys.nextElement();
      Object val = UIManager.get(key);
      if (val instanceof FontUIResource) {
        UIManager.put(key, uiFont);
      }
    }
  }
}

// call early in main():
// Fonts.applyUIFont(13f);

Respect system high contrast on Windows. Swing will not flip your colors for you. You can detect it and choose a palette with stronger contrast.

import java.awt.*;

public final class HighContrast {
  public static boolean isOn() {
    Object val = Toolkit.getDefaultToolkit().getDesktopProperty("win.highContrast.on");
    return Boolean.TRUE.equals(val);
  }
}

// usage:
// Color bg = HighContrast.isOn() ? Color.BLACK : Color.WHITE;
// Color fg = HighContrast.isOn() ? Color.WHITE : new Color(0x222222);

Add mnemonics and focus to make keyboard first flows smooth. Also wire the default button on the root pane so Enter does the right thing.

JButton save = new JButton("Save");
save.setMnemonic('S'); // Alt S on Windows and Linux
save.getAccessibleContext().setAccessibleName("Save");
save.getAccessibleContext().setAccessibleDescription("Save changes");

JTextField name = new JTextField(20);
name.getAccessibleContext().setAccessibleName("Customer name");

JRootPane root = frame.getRootPane();
root.setDefaultButton(save); // Enter triggers save

// Make sure focus is visible
UIManager.put("Button.focus", Boolean.TRUE);

Bind keys for custom widgets. If you roll your own list or table renderer, you need to map keys just like Swing does.

JComponent comp = myCustomWidget();

InputMap im = comp.getInputMap(JComponent.WHEN_FOCUSED);
ActionMap am = comp.getActionMap();

im.put(KeyStroke.getKeyStroke("UP"), "moveUp");
im.put(KeyStroke.getKeyStroke("DOWN"), "moveDown");
im.put(KeyStroke.getKeyStroke("ENTER"), "activate");

am.put("moveUp", new AbstractAction() {
  public void actionPerformed(java.awt.event.ActionEvent e) { moveSelection(-1); }
});
am.put("moveDown", new AbstractAction() {
  public void actionPerformed(java.awt.event.ActionEvent e) { moveSelection(1); }
});
am.put("activate", new AbstractAction() {
  public void actionPerformed(java.awt.event.ActionEvent e) { openSelected(); }
});

Expose names for readers. Swing components have an AccessibleContext. Set a name and a description that make sense when read aloud.

JCheckBox cb = new JCheckBox("Send email");
cb.getAccessibleContext().setAccessibleName("Send email to the customer");
cb.getAccessibleContext().setAccessibleDescription(
  "If checked, the system will send an email notification to the customer"
);

Choose a Look and Feel with intent. If your users live on Windows, the system look and feel blends with their theme. Nimbus gives a consistent look across platforms. Pick one and test with a reader.

private static void pickLaf() {
  try {
    // System feel on Windows workstations, else Nimbus as a safe cross platform pick
    boolean win = System.getProperty("os.name").toLowerCase().contains("win");
    String laf = win ? UIManager.getSystemLookAndFeelClassName()
                     : "javax.swing.plaf.nimbus.NimbusLookAndFeel";
    UIManager.setLookAndFeel(laf);
  } catch (Exception ignore) { }
}

Counterexamples that bite

Custom painting with hard coded grays. That slick gradient that looked cool on your laptop turns into unreadable chrome on a projector or in high contrast. If you paint, read colors from UI defaults and keep contrast strong.

Tiny fonts baked into components. Setting font on each field locks you in. Users change DPI and your layout breaks. Set the font once through UIManager and let components inherit.

Mouse only actions. A button that only responds to a click, no mnemonic, no default button, is a blocker. Wire keys for everything you can click.

Hidden focus. Removing focus rings for looks makes people lost. Keep focus cues visible. Test with Tab from the first field to the last and back.

A quick decision rubric for teams

  • Pick your Look and Feel and stick to it. System for native feel, Nimbus for consistency. Test both with your users if in doubt.
  • Set default font with DPI aware code. Do not set fonts on each control.
  • Check contrast against WCAG 2.0 ratios. Keep 4.5 to 1 for normal text, 3 to 1 for big text.
  • Wire the keyboard. Mnemonics on buttons and labels, default button on dialogs, arrow keys for lists and tables.
  • Name your components through AccessibleContext. Make the screen reader say what a human would say.
  • Respect system settings. Read high contrast flags, antialias hints, and caret blink rates where available.
  • Test with a reader. On Windows install the Java Access Bridge and try with NVDA or JAWS. On Mac try VoiceOver. On Linux try Orca.

Here is a tiny helper to check color contrast while you code. It follows the WCAG math and gives you a ratio you can print to logs.

import java.awt.Color;

public final class Contrast {
  public static double ratio(Color fg, Color bg) {
    double L1 = relLuminance(fg) + 0.05;
    double L2 = relLuminance(bg) + 0.05;
    double max = Math.max(L1, L2), min = Math.min(L1, L2);
    return max / min;
  }

  private static double relLuminance(Color c) {
    double[] rgb = { c.getRed(), c.getGreen(), c.getBlue() };
    for (int i = 0; i < rgb.length; i++) {
      double s = rgb[i] / 255.0;
      rgb[i] = s <= 0.03928 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4);
    }
    return 0.2126 * rgb[0] + 0.7152 * rgb[1] + 0.0722 * rgb[2];
  }
}

// usage:
// System.out.println(Contrast.ratio(Color.BLACK, Color.WHITE));

Tip: on Windows, the Java Access Bridge is a separate install. Make sure QA has it, and let testers try the flows with a reader before you ship.

Lesson learned

Good accessibility in desktop Java is not magic. It is a bunch of small choices you make early. Pick a clear Look and Feel and own it. Set a readable font size once and let it flow. Keep contrast strong whether the theme is light or dark. Make the keyboard first path smooth with mnemonics and focus. Give the screen reader words that make sense. Then run the app on the same machines your users have and try a full shift with just the keyboard. Bugs will show up fast. The payoff is real. People move faster, support gets quieter, and your app feels like it belongs on their desk.

Software Architecture Software Engineering

Post navigation

Previous post
Next post
  • Digital Experience (94)
    • Experience Strategy (19)
    • Experience-Driven Commerce (5)
    • Multi-Channel Experience (9)
    • Personalization & Targeting (21)
    • SEO & Performance (10)
  • Marketing Technologies (92)
    • Analytics & Measurement (14)
    • Content Management Systems (45)
    • Customer Data Platforms (4)
    • Digital Asset Management (8)
    • Marketing Automation (6)
    • MarTech Stack & Strategy (10)
    • Technology Buying & ROI (3)
  • Software Engineering (310)
    • Business of Software (20)
    • Code (30)
    • Development Practices (52)
    • Digital Transformation (21)
    • Engineering Management (25)
    • General Software (82)
    • Productivity & Workflow (30)
    • Software Architecture (85)
    • Technical Implementation (23)
  • 2025 (12)
  • 2024 (8)
  • 2023 (18)
  • 2022 (13)
  • 2021 (3)
  • 2020 (8)
  • 2019 (8)
  • 2018 (23)
  • 2017 (17)
  • 2016 (40)
  • 2015 (37)
  • 2014 (25)
  • 2013 (28)
  • 2012 (24)
  • 2011 (30)
  • 2010 (42)
  • 2009 (25)
  • 2008 (13)
  • 2007 (33)
  • 2006 (26)

Ab Testing Adobe Adobe Analytics Adobe Target AEM agile-methodologies Analytics architecture-patterns CDP CMS coding-practices content-marketing Content Supply Chain Conversion Optimization Core Web Vitals customer-education Customer Data Platform Customer Experience Customer Journey DAM Data Layer Data Unification documentation DXP Individualization java Martech metrics mobile-development Mobile First Multichannel Omnichannel Personalization product-strategy project-management Responsive Design Search Engine Optimization Segmentation seo spring Targeting Tracking user-experience User Journey web-development

©2025 CMO & CTO | WordPress Theme by SuperbThemes