Iconography

General

Jhana UI uses a unified, customizable and variable icon syntax, that all components understand. There are four ways to define an SVGIcon. Allowing for more and more features. Depending on how complex your requirements are. No matter which option, you will never specify the SVG tag. Instead, all of thsese will require you to define the SVGViewBox.

@leon8ix/jhana-ui

export type SVGViewBox = { w: number; h: number; x?: number; y?: number };

Reactivity

For hover, active and focus-visible states to work properly, you need to define the 'icon-root' class on the parent element.

/routes/icon-button/+page.svelte

<button class="btn icon-btn icon-root" class:active>
    <Icon {icon} width="1.5em" height="1.5em" hover="var(--cLighter)" active="var(--cAcc)" />
    <span>My Button</span>
</button>

Filled Icons

You specify the SVG path ('d' Attribute). Which will be filled with the correct color, depending on the context. Since SVG paths can contain multiple subpaths, any mono-color filled icon can be defined like this.

/lib/icons/filled-icon.ts

const iconFilled: SVGIcon = {
    box: { w: 960, h: 960, y: -960 },
    fill: 'M440-280H280q-83 0-141.5-58.5T80-480q0-83 58.5-141.5T280-680h160v80Z',
};

Stroked Icons

You specify the SVG path ('d' Attribute). Which will be stroked with the correct color, depending on the context. You can optionally set the stroke-width. Since SVG paths can contain multiple subpaths, any mono-color single-stroke-width icon can be defined like this.

/lib/icons/stroked-icon.ts

const iconStroked: SVGIcon = {
    box: { w: 960, h: 960, y: -960 },
    stroke: 'M440-280H280q-83 0-141.5-58.5T80-480q0-83 58.5-141.5T280-680h160v80Z',
    strength: 3, // Optional, default: 3.4
};

Custom SVG Icons

In case you need to use different opacities for different icon elements, or you want to use SVG shapes like circle, or some other advanced stuff, you are free to use this syntax. You have access to many CSS variables, so you can use any custom logic, while still being variable and unaware of the context. You must not include the SVG tag itself here, only its contents.

/lib/icons/svg-icon.ts

/*
- var(--color)    Static color passed to Icon
- var(--hover)    Static hover color passed to Icon
- var(--active)   Static active color passed to Icon
- var(--cIcon)    Reactive color, changes on hover or active,
                  if those colors are set, this is what the icons 
                  internally use by default
- var(--isHover)  Numbool, 0 or 1 depending on hover (state), 
                  no matter if hov color is set
- var(--isActive) Numbool, 0 or 1 depending on active (state/class) 
                  no matter if active color is set
*/
const iconColorSwatch: SVGIcon = {
    box: { w: 32, h: 32 },
    svg: `
        <style> .svg-cs-c-o { opacity: calc((1 - var(--isHover)) * 0.2 + 0.6) } </style>
        <circle cx="16" cy="16" r="12.5" fill="var(--cIcon)" />
        <circle cx="16" cy="16" r="6" fill="var(--cDark)" class="svg-cs-c-o" />
    `
};

Custom Snippet Icons

If you require the features from the 'SVG Icon' syntax, but want to integrate Svelte reactivity or you simply prefer having syntax highlighting, type checking and autocomplete, you might want to use Svelte snippets. In addition to having access to the same CSS variables, you can also use the snippet's props and do JS calculations or Svelte conditionals with them. The downside here, is that you will have to define the icon inside a Svelte component.

/lib/icons/SnippetIcon.svelte

<script lang="ts">
    import type { SVGIconProps } from '@leon8ix/jhana-ui';
</script>

{#snippet icon({ color, hover, active, trans }: SVGIconProps)}
    <!-- You can use those vars however you want -->
    <g fill="none" stroke="var(--cIcon)" stroke-width="4">
        <line class="line-lft" y1="-1" y2="-9" x1="-9" x2="+0" transform-origin="0 -9" />
        <line class="line-rgt" y2="-1" y1="-9" x2="+9" x1="+0" transform-origin="0 -9" />
        <line class="line-bot" y1="+8" y2="+8" x1="-10" x2="+10" />
    </g>
    <!-- You can style this in that Svelte component's style tag -->
{/snippet}

<Icon icon={{ snippet: icon, box: { x: -20, y: -20, w: 40, h: 40 } }} width="1.4em" />