# How to Ensure Consistent SVG Line Weight with Non-Scaling Stroke in React

> Learn how to ensure consistent SVG line weight in React using non-scaling stroke. Maintain constant stroke widths regardless of scale transformations for perfect SVGs.

- Repository: [Ege Chelebi/blog](https://github.com/woosal1337/blog)
- Tags: how-to-guide
- Published: 2026-08-06

---

**Add `vectorEffect="non-scaling-stroke"` to SVG elements to maintain constant stroke widths regardless of scale transformations.**

In the `woosal1337/blog` repository, SVG icons are rendered directly within TypeScript/React components like `IconLink`, `ViewAllButton`, and `BackButton`. When these components use fixed `strokeWidth` values combined with Tailwind sizing utilities such as `w-8 h-8`, the visual line weight scales with the viewBox, creating uneven aesthetics. The SVG specification provides a declarative fix that keeps strokes crisp at any resolution.

## Why SVG Strokes Scale Unexpectedly

By default, SVG stroke widths are subject to the coordinate system of the `viewBox`. When you resize an icon container—scaling the SVG up or down—the stroke grows or shrinks proportionally. In [`components/ds/icon-link.tsx`](https://github.com/woosal1337/blog/blob/main/components/ds/icon-link.tsx), the `<rect>` element at lines 44–46 defines a `strokeWidth="1.2"` that appears thicker when the parent wrapper expands, breaking visual consistency across the blog's design system.

## Solution: Using vector-effect="non-scaling-stroke"

The `vector-effect` attribute overrides coordinate-system scaling for specific geometric properties. Setting `vectorEffect="non-scaling-stroke"` instructs the browser to render the stroke in device-pixel units, independent of any transforms or viewBox scaling.

### Applying to Individual Elements

Target the specific shape elements in your components. In [`components/ds/icon-link.tsx`](https://github.com/woosal1337/blog/blob/main/components/ds/icon-link.tsx), modify the rectangle definition to include the non-scaling attribute:

```tsx
<rect
  x="1.5"
  y="3"
  width="13"
  height="10"
  rx="2"
  stroke="currentColor"
  strokeWidth="1.2"
  vectorEffect="non-scaling-stroke"
/>

```

Similarly, update [`components/ds/view-all-button.tsx`](https://github.com/woosal1337/blog/blob/main/components/ds/view-all-button.tsx) (lines 16–19) and [`components/ds/back-button.tsx`](https://github.com/woosal1337/blog/blob/main/components/ds/back-button.tsx) (lines 16–19) to ensure their respective arrow and link icons maintain consistent line weight at all sizes.

### Creating a Reusable Wrapper Component

Centralize the fix by creating a `SvgIcon` wrapper that applies the attribute to the root `<svg>` element. This ensures every icon in the blog benefits automatically without repetitive markup:

```tsx
type SvgProps = React.SVGProps<SVGSVGElement>;

export const SvgIcon = ({ children, ...props }: SvgProps) => (
  <svg vectorEffect="non-scaling-stroke" {...props}>
    {children}
  </svg>
);

```

Consume the wrapper in existing components to guarantee uniform stroke behavior:

```tsx
import { SvgIcon } from '@/components/ds/svg-icon';

export function MailIcon() {
  return (
    <SvgIcon viewBox="0 0 16 16" className="w-8 h-8 text-ink-soft">
      <rect x="1.5" y="3" width="13" height="10" rx="2"
            stroke="currentColor" strokeWidth="1.2" />
      <path d="m2.5 4.5 5.5 4 5.5-4"
            stroke="currentColor" strokeWidth="1.2"
            strokeLinecap="round" />
    </SvgIcon>
  );
}

```

## Implementation Steps

1.  **Identify SVG components** – Locate files relying on fixed `strokeWidth` values, specifically [`components/ds/icon-link.tsx`](https://github.com/woosal1337/blog/blob/main/components/ds/icon-link.tsx), [`components/ds/view-all-button.tsx`](https://github.com/woosal1337/blog/blob/main/components/ds/view-all-button.tsx), and [`components/ds/back-button.tsx`](https://github.com/woosal1337/blog/blob/main/components/ds/back-button.tsx).

2.  **Add the vector effect attribute** – Insert `vectorEffect="non-scaling-stroke"` to shape elements (e.g., `<rect>`, `<path>`, `<circle>`) or the root `<svg>` tag.

3.  **Preserve explicit strokeWidth values** – Keep your numeric `strokeWidth` declarations; they now represent pixel-exact thickness rather than relative units.

4.  **Centralize with a wrapper** – Create a shared `SvgIcon` component in [`components/ds/svg-icon.tsx`](https://github.com/woosal1337/blog/blob/main/components/ds/svg-icon.tsx) to apply the attribute globally and reduce duplication.

5.  **Run quality checks** – Execute `bun run check` and `bun run lint` to verify the added props comply with Biome linting rules used throughout the project.

## Summary

-   **Non-scaling strokes** prevent line weight from growing when SVGs are resized via CSS or container queries.
-   Apply `vectorEffect="non-scaling-stroke"` directly to shape elements in [`components/ds/icon-link.tsx`](https://github.com/woosal1337/blog/blob/main/components/ds/icon-link.tsx), [`view-all-button.tsx`](https://github.com/woosal1337/blog/blob/main/view-all-button.tsx), and [`back-button.tsx`](https://github.com/woosal1337/blog/blob/main/back-button.tsx), or use a shared wrapper for global consistency.
-   The `strokeWidth` attribute remains required and defines the exact pixel thickness rendered on screen.
-   Always run `bun run lint` after modifying JSX attributes to maintain codebase standards.

## Frequently Asked Questions

### What does vector-effect="non-scaling-stroke" do exactly?

It instructs the rendering engine to calculate stroke width in screen-coordinate space rather than user-coordinate space. This means transformations applied to the SVG—whether through CSS scale, viewBox scaling, or matrix transforms—do not affect the thickness of the lines, ensuring consistent SVG line weight across all display contexts.

### Should I apply non-scaling-stroke to every SVG element or just the root?

Apply it to the specific elements that draw strokes, such as `<path>`, `<rect>`, or `<circle>`, or apply it once to the root `<svg>` element to affect all children. In the `woosal1337/blog` codebase, applying it to individual shape elements within `IconLink` and `BackButton` provides granular control, while a wrapper component applies it globally.

### Does non-scaling-stroke affect performance?

No, `vector-effect="non-scaling-stroke"` has negligible performance impact. The browser computes the stroke geometry using a different coordinate system, but this calculation is highly optimized in modern rendering engines and does not introduce perceptible overhead in React applications.

### Can I use non-scaling-stroke with CSS instead of attributes?

While the CSS `vector-effect` property exists in some specifications, browser support is inconsistent compared to the presentation attribute. For maximum compatibility in the `woosal1337/blog` TypeScript/React environment, use the JSX prop `vectorEffect="non-scaling-stroke"` directly on the SVG elements.