mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 17:35:10 +03:00
## What kind of change does this PR introduce? Bug fix and internal tooling update. Resolves FE-3472. ## What is the current behavior? Custom Studio icons use inconsistent source stroke widths, and some child-level styling prevents component props from overriding them. Mixed custom and Lucide icon sets can therefore appear uneven. ## What is the new behavior? Custom stroke icons use a root-level `stroke-width="1.5"`; fill-only logos use `stroke="none"`. The build validates that contract and regenerated components preserve existing exports and props. Studio applies the same `1.5` weight across Reports categories and uses one shared destination icon mapping in the replication selector, destination rows and diagram. | Before | After | | --- | --- | | <img width="418" height="516" alt="56398" src="https://github.com/user-attachments/assets/6afa7042-e6be-40e7-9911-af2f61238c9d" /> | <img width="390" height="550" alt="CleanShot 2026-07-30 at 17 12 37@2x" src="https://github.com/user-attachments/assets/870f49cf-c8fa-40db-8be8-2eb5f264ff4a" /> | | <img width="510" height="734" alt="CleanShot 2026-07-30 at 17 19 28@2x" src="https://github.com/user-attachments/assets/a5b2c088-dcd2-4907-976b-5820794d06e3" /> | <img width="554" height="742" alt="CleanShot 2026-07-30 at 17 16 06@2x" src="https://github.com/user-attachments/assets/ed3a77c4-5d94-4ca7-b9e4-1403b725a981" /> | ## Testing At 100% zoom, compare custom and Lucide icon weight in: - Reports: **Add your first chart** and **Add block** - Database > Replication: the destination selector, destination rows and replication diagram - Command menu (`⌘K`): **Search Database Tables**, **Search RLS Policies**, **Search Edge Functions** and **Search Storage** - Authentication > Users: right-click a user row and compare the context-menu icons - Database > Schema Visualizer: open a table node overflow menu - A paused project: **Export your data > Download backups** <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added consistent destination icons across replication panels, rows, and diagrams. * Updated instance health and metric icons for clearer identification. * Standardized icon stroke weight and reduced default icon stroke thickness. * **Documentation** * Clarified custom icon requirements, default properties, and validation guidance. * **Bug Fixes** * Improved consistency of icon rendering across replication destinations and reports. * **Tests** * Added coverage for icon SVG validation and replication destination icon rendering. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
136 lines
5.1 KiB
Plaintext
136 lines
5.1 KiB
Plaintext
---
|
||
title: Icons
|
||
description: Icons make actions and navigation across Supabase easier.
|
||
---
|
||
|
||
## Principles
|
||
|
||
1. Paired: Icons should accompany text, as they aren’t often obvious enough on their own.
|
||
2. Clear: Icons should be legible at small sizes and unembellished. Let the text do the heavy lifting.
|
||
3. Consistent: Use the same icons for similar actions throughout Supabase. This makes the app easier to use.
|
||
|
||
## Tints
|
||
|
||
Use classes just like you would for [text](color-usage#text) to tint icons. For example:
|
||
|
||
```jsx
|
||
<BucketAdd className="text-foreground-muted" />
|
||
```
|
||
|
||
Just like text, don’t tint icons with `text-destructive` for destructive actions. There should be a confirmation dialog right after which can handle the destructive styling.
|
||
|
||
## UI icons
|
||
|
||
We rely on [Lucide](https://lucide.dev/icons/) for any standard UI icon needs.
|
||
|
||
## Custom icons
|
||
|
||
Create and use custom icons when Lucide doesn’t have the icon you need. Tap on an icon below to copy the JSX, SVG, or import path.
|
||
|
||
<Icons />
|
||
|
||
### Usage
|
||
|
||
```jsx
|
||
import { BucketAdd, InsertCode, ReplaceCode } from 'icons'
|
||
|
||
function app() {
|
||
return (
|
||
<>
|
||
<ReplaceCode className="text-light" strokeWidth={1} size={16} />
|
||
<InsertCode className="text-light" strokeWidth={1} size={16} />
|
||
<BucketAdd size={24} className="text-foreground-muted" />
|
||
</>
|
||
)
|
||
}
|
||
```
|
||
|
||
**Default props**: All icons default to `size={24}`. Stroke icons use `strokeWidth={1.5}` and fill-only icons use `stroke="none"`. These defaults come from the source SVG's root attributes and can be intentionally overridden at the call site.
|
||
|
||
### Adding new custom icons
|
||
|
||
Follow these steps to add a new custom icon to the Supabase icon library.
|
||
|
||
1. **Create SVG file**: Add your SVG file to `packages/icons/src/raw-icons/` with a kebab-case name (e.g., `my-new-icon.svg`). Make sure it follows these requirements:
|
||
- Exported at 24×24px with `viewBox="0 0 24 24"`
|
||
- Uses `stroke="currentColor"` for strokes (no hardcoded colors)
|
||
- Uses `stroke-width="1.5"`
|
||
- Uses `fill="none"` for fills (no hardcoded colors)
|
||
- Icon content is optically centered and around 18×18px within the 24×24 frame
|
||
- Any unnecessary elements like `<clipPath>`, `<defs>`, and `<g>` wrappers have been removed
|
||
- SVG structure is as simple as possible with just `<path>` elements
|
||
|
||
For **fill-only icons** (e.g. logos that use shapes instead of strokes), add `stroke="none"` to the root `<svg>` element. The build will propagate this so the component never renders an unwanted stroke.
|
||
|
||
Put shared styling like `fill`, `stroke`, `stroke-width`, `stroke-linecap`, and `stroke-linejoin` on the root `<svg>`. The build validates this contract, propagates the root attributes as the component's defaults, and converts them to camel-case for React compatibility (e.g. `strokeWidth`). Child-level stroke styling is rejected because it would override props passed to the component.
|
||
|
||
2. **Build the component**: Run `npm run build:icons` from inside the `packages/icons` directory
|
||
|
||
3. **Use the icon**: Import and use like any other icon:
|
||
|
||
```tsx
|
||
import { MyNewIcon } from 'icons'
|
||
```
|
||
|
||
```tsx
|
||
<MyNewIcon size={16} strokeWidth={1} />
|
||
```
|
||
|
||
The icon name is automatically made available in camel-case, determined by the kebab-case input SVG. For example, `my-new-icon.svg` will become available as `MyNewIcon`.
|
||
|
||
### SVG design guidelines
|
||
|
||
Icons should:
|
||
|
||
- Always be exported 24×24px
|
||
- Have an icon inside that frame that’s around 18×18px(ish)
|
||
- Use clean, simple paths without unnecessary wrapper elements
|
||
|
||
#### Bad example ❌
|
||
|
||
Notice the hardcoded colors, unnecessary backgrounds, and complex structure:
|
||
|
||
```svg
|
||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||
<rect width="24" height="24" fill="#1E1E1E" /> <!-- ❌ Hardcoded color -->
|
||
<path d="M..." fill="#404040" /> <!-- ❌ Hardcoded color -->
|
||
<path d="M..." stroke="#EDEDED" stroke-linecap="round" /> <!-- ❌ Hardcoded color -->
|
||
</svg>
|
||
```
|
||
|
||
#### Good example (stroke icon) ✅
|
||
|
||
Clean structure with `currentColor` and proper attributes:
|
||
|
||
```svg
|
||
<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||
<path d="M6 7C6 4.2 8.2 2 11 2H13C15.8 2 18 4.2 18 7" />
|
||
<path d="M4.5 11H19.5" />
|
||
<path d="M6 11L6.8 20C6.9 21.1 7.9 22 9 22H12" />
|
||
</svg>
|
||
```
|
||
|
||
#### Good example (fill-only icon / logo) ✅
|
||
|
||
Note `stroke="none"` on the root to prevent unwanted strokes, and `fill="currentColor"` on each path:
|
||
|
||
```svg
|
||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="none" xmlns="http://www.w3.org/2000/svg">
|
||
<path d="M..." fill="currentColor" />
|
||
</svg>
|
||
```
|
||
|
||
{/* This is still wrong: */}
|
||
|
||
```svg
|
||
<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||
<path d="M6 7C6 4.2 8.2 2 11 2H13C15.8 2 18 4.2 18 7" />
|
||
<path d="M4.5 11H19.5" />
|
||
<path d="M6 11L6.8 20C6.9 21.1 7.9 22 9 22H12" />
|
||
</svg>
|
||
```
|
||
|
||
### Troubleshooting
|
||
|
||
The icon build reports the source file and invalid attribute when an SVG does not follow the stroke or fill-only contract. Run `pnpm validate:icons` from `packages/icons` to check sources without regenerating components.
|