Svelte 5 wrapper for Kekule.js - render and edit organic compound structures from SMILES strings.
kekule-svelte provides Svelte 5 components for rendering and editing chemical molecular structures. It wraps Kekule.js, a powerful JavaScript library for chemoinformatics, and offers:
bun add kekule-svelte
# or
npm install kekule-svelte
<script lang="ts">
import { KekuleViewer } from 'kekule-svelte';
</script>
<!-- Render Aspirin -->
<KekuleViewer smiles="CC(=O)Oc1ccccc1C(=O)O" height="360px" />
A read-only 2D structure viewer. Renders molecular structures from SMILES strings with optional toolbar and mouse interaction.
<KekuleViewer
smiles="CCO"
width="100%"
height="360px"
showToolbar={false}
interactive={false}
background="transparent"
onReady={(viewer) => console.log('Ready:', viewer)}
onError={(error) => console.error('Error:', error)}
/>
| Prop | Type | Default | Description |
|---|---|---|---|
smiles |
string |
required | SMILES string to render |
width |
string |
'100%' |
CSS width |
height |
string |
'360px' |
CSS height |
showToolbar |
boolean |
false |
Show Kekule toolbar |
interactive |
boolean |
false |
Enable mouse pan/zoom |
background |
string |
'transparent' |
Canvas background color |
class |
string |
'' |
Additional CSS classes |
onReady |
function |
- | Callback when viewer is ready |
onError |
function |
- | Callback on render failure |
loading |
Snippet |
- | Custom loading indicator |
error |
Snippet |
- | Custom error display |
Use bind:this to access these methods:
<script lang="ts">
import { KekuleViewer } from 'kekule-svelte';
let ref = $state<any>();
</script>
<KekuleViewer smiles="CCO" bind:this={ref} />
<button onclick={() => ref?.downloadSVG('ethanol.svg')}>Download SVG</button>
| Method | Returns | Description |
|---|---|---|
getViewer() |
unknown |
Raw Kekule viewer instance |
exportSVG() |
string | null |
SVG data URI |
exportPNG() |
string | null |
PNG data URI |
downloadSVG(name) |
void |
Trigger SVG download |
downloadPNG(name) |
void |
Trigger PNG download |
A full interactive structure drawing editor powered by Kekule.js Composer. Emits SMILES on every structural change.
<script lang="ts">
import { KekuleEditor } from 'kekule-svelte';
let smiles = $state('');
</script>
<KekuleEditor
smiles="c1ccccc1"
height="480px"
onSmiles={(s) => (smiles = s)}
onReady={(editor) => console.log('Editor ready:', editor)}
/>
| Prop | Type | Default | Description |
|---|---|---|---|
smiles |
string |
'' |
Initial SMILES to load |
width |
string |
'100%' |
CSS width |
height |
string |
'480px' |
CSS height |
class |
string |
'' |
Additional CSS classes |
onSmiles |
function |
- | Callback with SMILES on change |
onChange |
function |
- | Callback with raw Kekule mol |
onReady |
function |
- | Callback when editor is ready |
loading |
Snippet |
- | Custom loading indicator |
| Method | Returns | Description |
|---|---|---|
getEditor() |
unknown |
Raw Kekule Composer instance |
getSmiles() |
string | null |
Current structure as SMILES |
getMolBlock() |
string | null |
Current structure as MOL block |
setSmiles(s) |
void |
Load new SMILES programmatically |
clear() |
void |
Clear the canvas |
undo() |
void |
Undo last action |
redo() |
void |
Redo last undone action |
downloadSVG(name) |
void |
Download current structure as SVG |
Renders a 2D reaction diagram from a reaction SMILES string.
<KekuleReaction
reaction="CCO.CC(=O)O>>CC(=O)OCC.O"
height="220px"
onReady={(viewer) => console.log('Ready:', viewer)}
onError={(error) => console.error('Error:', error)}
/>
Reaction SMILES format: reactant1.reactant2>>product1.product2 (multiple reactants or products separated by dots).
| Prop | Type | Default | Description |
|---|---|---|---|
reaction |
string |
required | Reaction SMILES string |
width |
string |
'100%' |
CSS width |
height |
string |
'220px' |
CSS height |
background |
string |
'transparent' |
Canvas background color |
class |
string |
'' |
Additional CSS classes |
onReady |
function |
- | Callback when viewer is ready |
onError |
function |
- | Callback on render failure |
loading |
Snippet |
- | Custom loading indicator |
error |
Snippet |
- | Custom error display |
A 3D molecular structure viewer using Kekule.js WebGL renderer. Renders molecules in 3D space with rotation and zoom controls.
<Kekule3DViewer
smiles="CCO"
height="400px"
renderMode="ballAndStick"
showToolbar={true}
onReady={(viewer) => console.log('3D Ready:', viewer)}
onError={(error) => console.error('Error:', error)}
/>
| Prop | Type | Default | Description |
|---|---|---|---|
smiles |
string |
'' |
SMILES string to render |
molBlock |
string |
'' |
MOL block content (alternative) |
width |
string |
'100%' |
CSS width |
height |
string |
'400px' |
CSS height |
showToolbar |
boolean |
false |
Show 3D viewer toolbar |
renderMode |
string |
'ballAndStick' |
Rendering mode (ballAndStick, spaceFill, wireframe, cylinder) |
background |
string |
'white' |
Canvas background color |
class |
string |
'' |
Additional CSS classes |
onReady |
function |
- | Callback when viewer is ready |
onError |
function |
- | Callback on render failure |
loading |
Snippet |
- | Custom loading indicator |
error |
Snippet |
- | Custom error display |
| Method | Returns | Description |
|---|---|---|
getViewer() |
unknown |
Raw Kekule 3D viewer instance |
exportSVG() |
string | null |
SVG data URI |
exportPNG() |
string | null |
PNG data URI |
downloadSVG(name) |
void |
Trigger SVG download |
downloadPNG(name) |
void |
Trigger PNG download |
rotate(x, y, z) |
void |
Rotate molecule |
zoomToFit() |
void |
Zoom to fit molecule |
import { loadKekule, isKekuleReady } from 'kekule-svelte';
// Load Kekule.js from CDN (singleton - safe to call multiple times)
const K = await loadKekule();
// Check if already loaded
if (isKekuleReady()) {
// Kekule.js is available
}
Kekule.js is loaded once from jsDelivr CDN when the first component mounts. Subsequent calls return the same Promise.
import { getMoleculeProperties, computeLipinski, formatFormula, loadKekule } from 'kekule-svelte';
// Get molecular properties from SMILES
const K = await loadKekule();
const props = getMoleculeProperties('CCO', K);
// Returns: { formula: 'C2H6O', molecularWeight: 46.07, atomCount: 9, ... }
// Check Lipinski's Rule of Five
const lipinski = computeLipinski({ mw: 180.16, logp: 1.19, hbd: 1, hba: 4 });
// Returns: { pass: true, rules: [...] }
// Format formula with subscript characters
formatFormula('C9H8O4'); // Returns 'C\u2089H\u2088O\u2084'
| Function | Description |
|---|---|
getMoleculeProperties(smiles, K) |
Extract MW, formula, ring count from SMILES |
computeFormula(atoms) |
Compute molecular formula in Hill notation |
computeMolecularWeight(atoms) |
Calculate molecular weight |
computeRingCount(bonds, atoms) |
Estimate ring count via Euler's formula |
computeLipinski(input) |
Lipinski's Rule of Five with per-rule breakdown |
formatFormula(formula) |
Convert ASCII digits to Unicode subscripts |
validateSmiles(smiles, K) |
Validate SMILES string syntax |
smilesToMol(smiles, K) |
Convert SMILES to MOL V2000 format |
smilesToSDF(smiles, K) |
Convert SMILES to SDF format |
smilesToSmarts(smiles, K) |
Convert SMILES to SMARTS pattern |
parseMolBlock(molBlock, K) |
Parse MOL block and return molecule object |
For SvelteKit applications with server-side rendering, use the SSR-safe entry point:
// In a +page.svelte or +layout.svelte
<script lang="ts">
import { onMount } from 'svelte';
let KekuleViewer: any;
onMount(async () => {
// Dynamic import ensures client-side only
const mod = await import('kekule-svelte/index-ssr');
KekuleViewer = mod.KekuleViewer;
});
</script>
{#if KekuleViewer}
<svelte:component this={KekuleViewer} smiles="CCO" />
{/if}
Use Svelte 5 snippets to customize loading and error displays:
<KekuleViewer smiles="CCO">
{#snippet loading()}
<div class="my-spinner">Loading molecule...</div>
{/snippet}
{#snippet error({ error })}
<div class="my-error">Failed to render: {error}</div>
{/snippet}
</KekuleViewer>
kekule-svelte loads Kekule.js from jsDelivr CDN the first time a component mounts. The loader is a singleton - it returns the same Promise regardless of how many components call it:
const K1 = await loadKekule();
const K2 = await loadKekule();
console.log(K1 === K2); // true
This library uses modern Svelte 5 patterns:
| React Pattern | Svelte 5 Equivalent |
|---|---|
useRef(null) |
let el = $state() + bind:this |
useEffect([deps]) |
$effect(() => { ... }) |
useEffect cleanup |
Return function from onMount |
useImperativeHandle |
export function getViewer() |
useState(initial) |
let value = $state(initial) |
| Render props | {#snippet name()}...{/snippet} |
Full documentation available at kekule-svelte.makeez.dev
MIT - Makeez Labs