I know this is an old question. I think I would like to resurrect it, because maybe someone knows how to solve this problem. I have only a "partial solution".
I very quickly implemented a border that does what you want. I reused what Java gives, i.e. Interpretation of HTML in swing components.
Everything works sweetly, the border is written perfectly for plain or HTML text, excluding the situation when you try to have different font sizes for texts.
I have no idea how to solve this problem. But I am very interested in the solution.
I know that the procedure will be to sum the width of each line in its own font size when calculating the variable textLengthInPixels.
The problem is that I don’t know how to get it, perhaps from a view, but I don’t know how?
import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Insets; import java.awt.Rectangle; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextField; import javax.swing.border.AbstractBorder; import javax.swing.border.Border; import javax.swing.border.LineBorder; import javax.swing.text.BadLocationException; import javax.swing.text.View; public class MultiColorTitleBorder extends AbstractBorder { private static final long serialVersionUID = 1L; private JLabel label; private int thicknessTop = 10; private Border border; private int thicknessLeft = 0; private int thicknessRight = 0; private int thicknessBottom = 0; public MultiColorTitleBorder(String title) { this.label = new JLabel(title); thicknessTop = label.getPreferredSize().height; } public MultiColorTitleBorder(String title, Border border) { this(title); this.border = border; thicknessLeft = border.getBorderInsets(null).left; thicknessRight = border.getBorderInsets(null).right; thicknessBottom = border.getBorderInsets(null).bottom; } @Override public synchronized void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { Graphics2D g2 = (Graphics2D) g; View view = (View) label.getClientProperty("html"); String text = label.getText(); FontMetrics fm = g2.getFontMetrics(label.getFont()); int bY = y + fm.getAscent() - ((fm.getAscent() + fm.getDescent())) / 2; if(border != null) { Insets in = border.getBorderInsets(c); g2.setClip(x, y, thicknessLeft * 2, height); border.paintBorder(c, g, x, bY, width, height - bY); try { if(view != null) text = view.getDocument().getText(0, view.getDocument().getLength()); }catch(BadLocationException ex) { Logger.getLogger(MultiColorTitleBorder.class.getName()).log(Level.SEVERE, null, ex); } int textLengthInPixels = fm.stringWidth(text); System.out.println("textLengthInPixels=" + textLengthInPixels); g2.setClip(x +thicknessLeft * 2+ textLengthInPixels, y, width - thicknessLeft * 2 -textLengthInPixels, height); border.paintBorder(c, g, x, bY, width, height - bY); int bottomIn = in.bottom; g2.setClip(x, height - bottomIn, width, bottomIn); border.paintBorder(c, g, x, bY, width, height - bY); g2.setClip(x, y, width, height); } if(view != null) view.paint(g2, new Rectangle(x + thicknessLeft * 2, y, width - thicknessLeft * 2, height)); else { Font prevFont = g2.getFont(); g2.setFont(label.getFont()); g2.drawString(text, x + thicknessLeft * 2, fm.getAscent()); g2.setFont(prevFont); } } @Override public Insets getBorderInsets(Component c) { return new Insets(thicknessTop, thicknessLeft, thicknessBottom, thicknessRight); } @Override public Insets getBorderInsets(Component c, Insets insets) { insets.top = thicknessTop; insets.left = thicknessLeft; insets.right = thicknessRight; insets.bottom = thicknessBottom; return insets; } @Override public boolean isBorderOpaque() { return false; } public static void main(String[] args) { JPanel p = new JPanel(); p.setPreferredSize(new Dimension(200, 200)); String title = "<html><color=red> Text 1</font><font color=blue> Text 2</font>";