Borders
Borders define the edge of a surface and separate content within it. A border is three decisions: width, style, and color. Use the hairline token for width, solid for style, and a semantic token for color.
- Set width with
borderWidth(or a side, e.g.borderBottomWidth). - Set style with
borderStyleand color withborderColor. - Default to
borderWidth="hairline",borderStyle="solid",borderColor="base.border".
#
hairline is the default border width — and it's density-adaptive:
1pxon standard displays, so borders stay visible.0.5pxon high-DPI / retina displays (≥2x), so borders look crisp and refined.
It's a borderWidth token backed by the --chakra-border-hairline CSS variable, so a single token gives the right weight on every screen. Compose it with a style and color rather than using it alone.
When to use
- Resting borders on inputs, selects, comboboxes, textareas, badges, cards, menus, popovers, avatars, and icon boxes.
- Dividers between rows, sections, and groups inside a surface.
When not to use
- When you need a fixed width regardless of screen density — use a literal
1px/2px. - For focus rings — use the
outlineshadow (see Shadows), never a thicker border.
Avoid
- Hardcoding
0.5pxor1pxfor standard borders — usehairlineso density is handled for you. - In-between widths like
0.75pxor1.5px— stick tohairline, or a fixed1px/2pxfor emphasis. - Using
hairlinealone; always pair it withborderStyleandborderColor.
#
In theme component configs, import the $borderHairline CSS variable and compose it into the border shorthand:
#
Border color is always a semantic token, never a raw hex or palette step. base.border is the default; reach for an intent color only when the border itself communicates status.
base.border— the outer edge of a surface (input, card, badge, menu).base.divider— separators inside a surface (table rows, list items, sections). It's lighter thanbase.borderso internal structure recedes.- Intent borders (
primary,danger,warning,success,upsell) — only when the border carries meaning, e.g. an invalid field or a selected option.
#
Use base.border for the edge of a surface and base.divider for separators within it. The divider is one step lighter so the container reads as the dominant shape.
#
solidis the default for every border.dashedis reserved for pending, placeholder, or not-yet-committed states (e.g. a pending badge). Don't use it for decoration.
#
Borders and shadows do different jobs. A border defines an edge; a shadow lifts a surface off the canvas.
- Use a
hairlineborder for definition on a flat surface that sits on the page. - Use a shadow for elevation (menus, popovers, modals).
- Some elements use both — inputs pair a
hairlineborder with thebuttonShadowLightshadow. - Avoid stacking a visible border with a large elevation shadow; it creates a doubled edge.
#
- Do default to
borderWidth="hairline"+borderStyle="solid"+borderColor="base.border". - Do use
base.dividerfor separators inside a surface. - Do match the border color to intent (
danger.borderon an invalid field). - Don't hardcode
0.5pxor1pxfor standard borders — usehairline. - Don't use a border to signal focus — use the
outlineshadow. - Don't reach for raw colors (
gray.300, hex) when a semantic token exists.
#
- Border Radius — corner rounding and nesting.
- Colors — the full semantic color palette.
- Shadows — elevation and depth.