Tipex is architected with customization as a core principle. Every aspect of the editor can be tailored to match your application's design system and functional requirements. This comprehensive guide covers everything from basic styling to advanced extension development.
Tipex offers multiple layers of customization:
Tipex uses Tailwind CSS v4 with the modern `@theme` configuration system and CSS custom properties for comprehensive theming. You can override any aspect of the visual design using the new Tailwind v4 architecture:
/* Modern Tailwind v4 Theme Configuration - Based on Tipex Design System */
@import "tailwindcss";
@theme {
/* Override Tipex Design System Colors */
--color-tipex-*: initial;
/* Tipex Grayscale Colors (50-950) - Override defaults */
--color-tipex-50: oklch(0.99 0 0);
--color-tipex-100: oklch(0.975 0 0);
--color-tipex-200: oklch(0.93 0 0);
--color-tipex-300: oklch(0.88 0 0);
--color-tipex-400: oklch(0.72 0 0);
--color-tipex-500: oklch(0.57 0 0);
--color-tipex-600: oklch(0.45 0 0);
--color-tipex-700: oklch(0.38 0 0);
--color-tipex-800: oklch(0.28 0 0);
--color-tipex-900: oklch(0.22 0 0);
--color-tipex-950: oklch(0.15 0 0);
/* Tipex Success Colors (Green) - Override defaults */
--color-tipex-success-50: oklch(0.985 0.008 140);
--color-tipex-success-100: oklch(0.972 0.015 140);
--color-tipex-success-200: oklch(0.93 0.045 140);
--color-tipex-success-300: oklch(0.875 0.09 140);
--color-tipex-success-400: oklch(0.775 0.16 140);
--color-tipex-success-500: oklch(0.65 0.21 140);
--color-tipex-success-600: oklch(0.55 0.21 140);
--color-tipex-success-700: oklch(0.47 0.185 140);
--color-tipex-success-800: oklch(0.39 0.15 140);
--color-tipex-success-900: oklch(0.33 0.12 140);
--color-tipex-success-950: oklch(0.21 0.08 140);
/* Tipex Primary Colors (Indigo) - Override defaults */
--color-tipex-primary-50: oklch(0.985 0.004 270);
--color-tipex-primary-100: oklch(0.972 0.008 270);
--color-tipex-primary-200: oklch(0.93 0.022 270);
--color-tipex-primary-300: oklch(0.875 0.045 270);
--color-tipex-primary-400: oklch(0.775 0.08 270);
--color-tipex-primary-500: oklch(0.65 0.1 270);
--color-tipex-primary-600: oklch(0.55 0.1 270);
--color-tipex-primary-700: oklch(0.47 0.085 270);
--color-tipex-primary-800: oklch(0.39 0.07 270);
--color-tipex-primary-900: oklch(0.33 0.058 270);
--color-tipex-primary-950: oklch(0.21 0.045 270);
/* Spacing Scale - Override defaults */
--spacing-tipex-xs: 0.25rem;
--spacing-tipex-sm: 0.5rem;
--spacing-tipex-md: 1rem;
--spacing-tipex-lg: 1.5rem;
--spacing-tipex-xl: 2rem;
--spacing-tipex-2xl: 2.5rem;
/* Sizing Scale - Override defaults */
--size-tipex-1: 0.25rem;
--size-tipex-2: 0.5rem;
--size-tipex-3: 0.75rem;
--size-tipex-4: 1rem;
--size-tipex-5: 1.25rem;
--size-tipex-6: 1.5rem;
--size-tipex-7: 1.75rem;
--size-tipex-8: 2rem;
--size-tipex-9: 2.25rem;
--size-tipex-10: 2.5rem;
--size-tipex-11: 2.75rem;
--size-tipex-12: 3rem;
/* Border Radius - Override defaults */
--radius-tipex-sm: 0.25rem;
--radius-tipex-md: 0.375rem;
/* Typography Scale - Override defaults */
--text-tipex-xs: 0.75rem;
--text-tipex-sm: 0.875rem;
--text-tipex-base: 1rem;
--text-tipex-lg: 1.125rem;
--text-tipex-xl: 1.25rem;
--text-tipex-2xl: 1.5rem;
/* Z-Index - Override defaults */
--z-tipex-floating: 50;
--z-tipex-controls: 10;
/* Custom additions (not in default theme) */
--shadow-tipex-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
--shadow-tipex-md: 0 4px 6px -1px rgb(0 0 0 / 0.1);
--shadow-tipex-focus: 0 0 0 3px rgb(139 92 246 / 0.5);
}
/* Custom Dark Mode Variant (Tailwind v4) */
@custom-variant dark (&:where(.dark, .dark *));
/* Component Layer Customization */
@layer components {
.tipex-editor {
@apply bg-tipex-50 dark:bg-tipex-950
border border-tipex-200 dark:border-tipex-800
rounded-radius-tipex-md;
}
.tipex-editor.focused.focal {
@apply shadow-tipex-focus
border-tipex-primary-500 dark:border-tipex-primary-400
outline-none;
}
.tipex-controls {
@apply bg-tipex-100 dark:bg-tipex-900
border border-tipex-200 dark:border-tipex-800
rounded-radius-tipex-sm;
}
} Tipex provides a single, flexible way to customize the editor controls through the `controlComponent` slot. You can either extend the default controls with custom utilities or completely replace them with your own implementation.
Include the default controls and utility buttons (copy, link management) in your editor:
import { Tipex, Controls } from "@friendofsvelte/tipex";
<Tipex body={body}>
{#snippet controlComponent(tipex)}
<Controls {tipex}>
<!-- Built-in utilities: copy HTML and link editing with clipboard integration -->
<!-- Additional utility buttons can be added here -->
<button class="tipex-edit-button tipex-button-rigid" aria-label="Custom action">
<ICONHERE />
</button>
</Controls>
{/snippet}
</Tipex> Add your own custom buttons alongside the built-in utilities:
<Tipex body={body}>
{#snippet controlComponent(tipex)}
<Controls {tipex}>
<!-- Built-in utilities: copy HTML and link editing with clipboard integration -->
<!-- Add custom utilities here -->
<button class="tipex-edit-button tipex-button-rigid" aria-label="Export PDF">
<ICONHERE />
</button>
</Controls>
{/snippet}
</Tipex> Here's a more comprehensive example with multiple custom utilities:
<Tipex body={body}>
{#snippet controlComponent(tipex)}
<Controls {tipex}>
<!-- Built-in utilities: copy HTML and link editing with clipboard integration -->
<!-- Add your custom utilities here -->
<button
class="tipex-edit-button tipex-button-rigid"
onclick={() => exportToPDF(tipex.getHTML())}
aria-label="Export to PDF"
>
<ICONHERE />
</button>
<button
class="tipex-edit-button tipex-button-rigid"
onclick={() => insertTemplate(tipex)}
aria-label="Insert template"
>
<ICONHERE />
</button>
<button
class="tipex-edit-button tipex-button-rigid"
onclick={() => toggleFullscreen()}
aria-label="Toggle fullscreen"
>
<ICONHERE />
</button>
</Controls>
{/snippet}
</Tipex> | Prop Name | Default | Condition | Description |
|---|---|---|---|
| head(tipex) | undefined | Optional | A slot that accepts a function receiving the TipexEditor instance, rendered above the main editor content area |
| controlComponent | Snippet<[TipexEditor]> | null | Optional | A slot that accepts a function receiving the TipexEditor instance, used to completely replace the default controls. Set to null to hide all controls completely. |
| foot(tipex) | undefined | Optional | A slot that accepts a function receiving the TipexEditor instance, rendered below the editor content and controls |
Tipex automatically detects which control system to use:
controlComponent is provided: Uses your custom control componentcontrolComponent is not provided: Shows default controls with built-in utilitiescontrolComponent={null}: Hides all controls completely (no toolbar)This ensures a clean API where you don't need to manage boolean flags.
Replace the entire control system with your own custom implementation:
<Tipex body={body}>
{#snippet controlComponent(tipex)}
<div aria-label="New Custom Control">...</div>
{/snippet}
</Tipex> Here's a complete custom control implementation:
<script>
import CustomToolbar from './CustomToolbar.svelte';
</script>
<Tipex body={body}>
{#snippet controlComponent(tipex)}
<CustomToolbar {tipex} />
{/snippet}
</Tipex>
<!-- CustomToolbar.svelte -->
<script>
export let tipex;
let isActive = $derived((name, attrs = {}) => tipex?.isActive(name, attrs) ?? false);
let canExecute = $derived((command) => tipex?.can()[command]() ?? false);
</script>
<div class="custom-toolbar">
<div class="toolbar-section">
<button
class="toolbar-btn"
class:active={isActive('bold')}
disabled={!canExecute('toggleBold')}
onclick={() => tipex.chain().focus().toggleBold().run()}
>
<strong>B</strong>
</button>
<button
class="toolbar-btn"
class:active={isActive('italic')}
onclick={() => tipex.chain().focus().toggleItalic().run()}
>
<em>I</em>
</button>
</div>
<div class="toolbar-section">
<select
value={isActive('heading', {level: 1}) ? '1' :
isActive('heading', {level: 2}) ? '2' : 'p'}
onchange={(e) => {
const level = e.target.value;
if (level === 'p') {
tipex.chain().focus().setParagraph().run();
} else {
tipex.chain().focus().toggleHeading({level: parseInt(level)}).run();
}
}}
>
<option value="p">Paragraph</option>
<option value="1">Heading 1</option>
<option value="2">Heading 2</option>
</select>
</div>
</div>
<style>
@reference "../app.css";
.custom-toolbar {
@apply flex gap-spacing-tipex-md p-spacing-tipex-lg
bg-tipex-100 dark:bg-tipex-900
rounded-radius-tipex-md
border border-tipex-200 dark:border-tipex-800;
}
.toolbar-btn {
@apply px-spacing-tipex-sm py-spacing-tipex-xs
bg-tipex-50 dark:bg-tipex-950
border border-tipex-200 dark:border-tipex-800
rounded-radius-tipex-sm
hover:bg-tipex-100 dark:hover:bg-tipex-800
focus:outline-none focus:ring-2 focus:ring-tipex-primary-500/40;
}
.toolbar-btn.active {
@apply bg-tipex-primary-100 dark:bg-tipex-primary-900
border-tipex-primary-300 dark:border-tipex-primary-700
text-tipex-primary-700 dark:text-tipex-primary-300;
}
</style> IMPORTANT: Tipex exclusively uses and requires Tailwind CSS v4. We do NOT support older versions (v1.x, v2.x, v3.x) as they lack the modern architecture required for Tipex's advanced theming system.
@theme configuration@custom-variant syntax for advanced dark modeTipex exclusively uses Tailwind CSS v4 for superior developer experience and performance:
Upgrade to Tailwind v4 immediately for the best Tipex experience. The new architecture is essential for Tipex's theming system to function properly.
Migration Note: If you're using older Tailwind versions (v1.x, v2.x, v3.x), you MUST upgrade to Tailwind v4 for Tipex to work correctly. The new architecture provides significantly better performance, developer experience, and maintainability.
Tipex supports comprehensive layout customization through multiple slot areas:
<script lang="ts">
import { Tipex } from "@friendofsvelte/tipex";
import type { Editor } from '@tiptap/core';
import DocumentHeader from "./DocumentHeader.svelte";
import DocumentFooter from "./DocumentFooter.svelte";
import CustomToolbar from "./CustomToolbar.svelte";
let editor = $state<Editor>();
let wordCount = $state(0);
let lastSaved = $state<Date | null>(null);
// Reactive word count using runes
$effect(() => {
if (editor) {
const text = editor.getText();
wordCount = text.split(/\s+/).filter(word => word.length > 0).length;
}
});
// Auto-save functionality using runes
$effect(() => {
if (editor) {
const debounceTimer = setTimeout(() => {
saveDocument(editor.getHTML());
lastSaved = new Date();
}, 2000);
return () => clearTimeout(debounceTimer);
}
});
async function saveDocument(content: string) {
try {
await fetch('/api/documents/save', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ content, timestamp: new Date().toISOString() })
});
} catch (error) {
console.error('Auto-save failed:', error);
}
}
</script>
<Tipex bind:tipex={editor} body={body}>
{#snippet head(tipex)}
<DocumentHeader
{wordCount}
{lastSaved}
characterCount={tipex.getText().length}
readingTime={Math.ceil(wordCount / 200)}
/>
{/snippet}
{#snippet controlComponent(tipex)}
<CustomToolbar
{tipex}
onSave={() => saveDocument(tipex.getHTML())}
onExport={() => exportDocument(tipex.getHTML())}
/>
{/snippet}
{#snippet foot(tipex)}
<DocumentFooter
status={lastSaved ? 'saved' : 'unsaved'}
{wordCount}
version="1.2.3"
/>
{/snippet}
</Tipex> Here's a practical example with a custom header featuring document statistics:
<script>
import { Tipex } from "@friendofsvelte/tipex";
import DocumentStats from "./DocumentStats.svelte";
import CustomControl from "./CustomControl.svelte";
import SaveIndicator from "./SaveIndicator.svelte";
let editor = $state();
let lastSaved = $state(null);
// Auto-save functionality using runes
$effect(() => {
if (editor) {
const debounce = setTimeout(() => {
saveDocument(editor.getHTML());
lastSaved = new Date();
}, 1000);
return () => clearTimeout(debounce);
}
});
</script>
<Tipex bind:tipex={editor} body={body}>
{#snippet head(tipex)}
<div class="editor-header">
<DocumentStats {tipex} />
<SaveIndicator {lastSaved} />
</div>
{/snippet}
{#snippet controlComponent(tipex)}
<CustomControl {tipex} />
{/snippet}
{#snippet foot(tipex)}
<div class="editor-footer">
<span class="status">Ready</span>
<span class="word-count">{getWordCount(tipex)} words</span>
</div>
{/snippet}
</Tipex> Tipex provides flexible image handling. You can customize the upload process, validation, and storage:
<script>
import { Tipex } from "@friendofsvelte/tipex";
async function handleImageUpload(file) {
// Custom validation
const maxSize = 5 * 1024 * 1024; // 5MB
const allowedTypes = ['image/jpeg', 'image/png', 'image/webp'];
if (!allowedTypes.includes(file.type)) {
throw new Error('Unsupported file type');
}
if (file.size > maxSize) {
throw new Error('File too large');
}
// Upload to your service (Cloudinary, AWS S3, etc.)
const formData = new FormData();
formData.append('image', file);
const response = await fetch('/api/upload', {
method: 'POST',
body: formData
});
if (!response.ok) throw new Error('Upload failed');
const { url, publicId } = await response.json();
return {
src: url,
alt: file.name,
'data-public-id': publicId // For later deletion
};
}
let editor;
</script>
<Tipex bind:tipex={editor} body={body}>
{#snippet controlComponent(tipex)}
<div class="custom-image-controls">
<!-- Built-in controls would go here if using Controls component -->
<button
class="tipex-edit-button tipex-button-rigid"
onclick={() => {
const input = document.createElement('input');
input.type = 'file';
input.accept = 'image/*';
input.onchange = async (e) => {
const file = e.target.files[0];
if (file) {
try {
const imageData = await handleImageUpload(file);
tipex.commands.setImage(imageData);
} catch (error) {
alert('Upload failed: ' + error.message);
}
}
};
input.click();
}}
aria-label="Upload image"
>
📷 Upload Image
</button>
<button
class="tipex-edit-button tipex-button-rigid"
onclick={() => tipex.commands.toggleBold()}
aria-label="Toggle bold"
>
<strong>B</strong>
</button>
<button
class="tipex-edit-button tipex-button-rigid"
onclick={() => tipex.commands.toggleItalic()}
aria-label="Toggle italic"
>
<em>I</em>
</button>
</div>
{/snippet}
</Tipex> Leverage TipTap's powerful extension system to add custom functionality. Tipex provides easy access to modify and extend the editor's capabilities:
Customize the built-in extensions to match your requirements:
<script lang="ts">
import { defaultExtensions, Tipex } from "@friendofsvelte/tipex";
import { Heading } from '@tiptap/extension-heading';
import { TextAlign } from '@tiptap/extension-text-align';
import { Highlight } from '@tiptap/extension-highlight';
import { Underline } from '@tiptap/extension-underline';
import { Table } from '@tiptap/extension-table';
import { TableRow } from '@tiptap/extension-table-row';
import { TableHeader } from '@tiptap/extension-table-header';
import { TableCell } from '@tiptap/extension-table-cell';
import type { Extensions } from '@tiptap/core';
// Custom extension configuration
const customExtensions: Extensions = [
...defaultExtensions.filter(ext => ext.name !== 'heading'), // Remove default heading
// Custom heading configuration
Heading.configure({
levels: [1, 2, 3, 4], // Only allow H1-H4
HTMLAttributes: {
class: 'custom-heading',
},
}),
// Text alignment support
TextAlign.configure({
types: ['heading', 'paragraph'],
alignments: ['left', 'center', 'right', 'justify'],
defaultAlignment: 'left',
}),
// Highlighting with multiple colors
Highlight.configure({
multicolor: true,
HTMLAttributes: {
class: 'custom-highlight',
},
}),
// Underline support
Underline.configure({
HTMLAttributes: {
class: 'custom-underline',
},
}),
// Table support
Table.configure({
resizable: true,
HTMLAttributes: {
class: 'custom-table',
},
}),
TableRow,
TableHeader,
TableCell,
];
let body = `
<h1>Welcome to Enhanced Tipex</h1>
<p>This editor now supports:</p>
<ul>
<li>Custom heading levels (H1-H4 only)</li>
<li>Text alignment options</li>
<li><mark data-color="#ffeb3b">Multi-color highlighting</mark></li>
<li><u>Underlined text</u></li>
<li>Resizable tables</li>
</ul>
`;
</script>
<Tipex extensions={customExtensions} {body} /> Build your own extensions for specialized functionality:
<script>
import { Extension } from '@tiptap/core';
import { defaultExtensions, Tipex } from "@friendofsvelte/tipex";
// Custom extension for highlighting text
const Highlight = Extension.create({
name: 'highlight',
addOptions() {
return {
multicolor: true,
HTMLAttributes: {},
};
},
addGlobalAttributes() {
return [
{
types: ['textStyle'],
attributes: {
backgroundColor: {
default: null,
parseHTML: element => element.style.backgroundColor,
renderHTML: attributes => {
if (!attributes.backgroundColor) return {};
return { style: `background-color: ${attributes.backgroundColor}` };
},
},
},
},
];
},
addCommands() {
return {
setHighlight: (attributes) => ({ commands }) => {
return commands.setMark('textStyle', attributes);
},
toggleHighlight: (attributes) => ({ commands }) => {
return commands.toggleMark('textStyle', attributes);
},
unsetHighlight: () => ({ commands }) => {
return commands.unsetMark('textStyle');
},
};
},
});
// Custom extension for word count
const WordCount = Extension.create({
name: 'wordCount',
addStorage() {
return {
wordCount: 0,
characterCount: 0,
};
},
onUpdate() {
const text = this.editor.getText();
this.storage.wordCount = text.split(/\\s+/).filter(word => word.length > 0).length;
this.storage.characterCount = text.length;
},
});
const customExtensions = [
...defaultExtensions,
Highlight,
WordCount,
// Add more custom extensions
];
</script>
<Tipex extensions={customExtensions} body={body}>
{#snippet controlComponent(tipex)}
<div class="custom-controls">
<!-- Highlight controls -->
<button
onclick={() => tipex.commands.setHighlight({ backgroundColor: '#ffeb3b' })}
class="tipex-edit-button"
>
<ICONHERE />
</button>
<!-- Word count display -->
<span class="word-count">
Words: {tipex.storage.wordCount?.wordCount || 0}
</span>
</div>
{/snippet}
</Tipex> React to editor events for dynamic behavior and integrations:
<script>
import { Tipex } from "@friendofsvelte/tipex";
let editor = $state();
let isTyping = $state(false);
let typingTimer;
function handleEditorReady(tipex) {
// Auto-save setup
tipex.on('update', ({ editor }) => {
clearTimeout(typingTimer);
isTyping = true;
typingTimer = setTimeout(() => {
isTyping = false;
saveContent(editor.getHTML());
}, 1000);
});
// Custom keyboard shortcuts
tipex.on('keydown', (event) => {
// Ctrl+S for save
if (event.ctrlKey && event.key === 's') {
event.preventDefault();
saveContent(tipex.getHTML());
}
// Ctrl+Shift+L for link
if (event.ctrlKey && event.shiftKey && event.key === 'L') {
event.preventDefault();
const url = prompt('Enter URL:');
if (url) {
tipex.commands.setLink({ href: url });
}
}
});
// Selection change handling
tipex.on('selectionUpdate', ({ editor }) => {
updateFloatingMenu(editor);
});
// Focus/blur handling
tipex.on('focus', () => {
document.body.classList.add('editor-focused');
});
tipex.on('blur', () => {
document.body.classList.remove('editor-focused');
});
}
async function saveContent(html) {
try {
await fetch('/api/save', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ content: html })
});
} catch (error) {
console.error('Save failed:', error);
}
}
</script>
<Tipex
bind:tipex={editor}
body={body}
onready={handleEditorReady}
>
{#snippet head()}
<div class="editor-status">
{#if isTyping}
<span class="status typing">Typing...</span>
{:else}
<span class="status saved">Saved</span>
{/if}
</div>
{/snippet}
</Tipex> Enhance accessibility with custom ARIA labels, keyboard navigation, and screen reader support:
<script>
function enhanceAccessibility(tipex) {
// Add custom ARIA labels
const editorElement = tipex.view.dom;
editorElement.setAttribute('aria-label', 'Rich text editor');
editorElement.setAttribute('role', 'textbox');
editorElement.setAttribute('aria-multiline', 'true');
// Custom keyboard shortcuts for accessibility
tipex.on('keydown', (event) => {
// Alt+1-6 for headings
if (event.altKey && event.key >= '1' && event.key <= '6') {
event.preventDefault();
const level = parseInt(event.key);
tipex.commands.toggleHeading({ level });
// Announce to screen readers
announceToScreenReader(`Heading level ${level} applied`);
}
// Alt+L for list
if (event.altKey && event.key === 'l') {
event.preventDefault();
tipex.commands.toggleBulletList();
announceToScreenReader('Bullet list toggled');
}
});
}
function announceToScreenReader(message) {
const announcement = document.createElement('div');
announcement.setAttribute('aria-live', 'polite');
announcement.setAttribute('aria-atomic', 'true');
announcement.className = 'sr-only';
announcement.textContent = message;
document.body.appendChild(announcement);
setTimeout(() => document.body.removeChild(announcement), 1000);
}
</script>
<Tipex
body={body}
onready={enhanceAccessibility}
aria-label="Document editor"
>
{#snippet controlComponent(tipex)}
<div class="accessible-controls" role="toolbar" aria-label="Formatting options">
<button
class="tipex-edit-button"
class:active={tipex.isActive('bold')}
onclick={() => tipex.commands.toggleBold()}
aria-label="Toggle bold formatting"
aria-pressed={tipex.isActive('bold')}
>
<strong>B</strong>
</button>
<button
class="tipex-edit-button"
class:active={tipex.isActive('italic')}
onclick={() => tipex.commands.toggleItalic()}
aria-label="Toggle italic formatting"
aria-pressed={tipex.isActive('italic')}
>
<em>I</em>
</button>
</div>
{/snippet}
</Tipex>
<style>
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
</style> Optimize your customized editor using Tailwind v4's performance benefits:
Tailwind v4's modern architecture provides up to 50% faster builds and 30% smaller CSS bundles compared to v3.x, making your Tipex editor load faster and perform better.
Best Practices with Tailwind v4: When customizing Tipex, leverage Tailwind v4's `@layer components`, `@theme` configuration, and `@custom-variant` features. Always test your changes across different devices and browsers. The modern Tailwind v4 architecture ensures better performance and maintainability compared to legacy versions.
Create sophisticated themes using Tailwind v4's advanced features. Here's a complete example of a premium theme configuration:
/* Premium Tipex Theme with Tailwind v4 - Using Actual Design System */
@import "tailwindcss";
@theme {
/* Override Tipex Design System with Premium Colors */
--color-tipex-*: initial;
/* Premium Grayscale Palette (OKLCH for better color accuracy) */
--color-tipex-50: oklch(0.99 0 0);
--color-tipex-100: oklch(0.975 0 0);
--color-tipex-200: oklch(0.925 0 0);
--color-tipex-300: oklch(0.875 0 0);
--color-tipex-400: oklch(0.715 0 0);
--color-tipex-500: oklch(0.565 0 0);
--color-tipex-600: oklch(0.445 0 0);
--color-tipex-700: oklch(0.375 0 0);
--color-tipex-800: oklch(0.275 0 0);
--color-tipex-900: oklch(0.215 0 0);
--color-tipex-950: oklch(0.15 0 0);
/* Premium Success Colors (Emerald Green) */
--color-tipex-success-50: oklch(0.985 0.008 145);
--color-tipex-success-100: oklch(0.972 0.015 145);
--color-tipex-success-200: oklch(0.93 0.045 145);
--color-tipex-success-300: oklch(0.875 0.09 145);
--color-tipex-success-400: oklch(0.775 0.16 145);
--color-tipex-success-500: oklch(0.65 0.21 145);
--color-tipex-success-600: oklch(0.55 0.21 145);
--color-tipex-success-700: oklch(0.47 0.185 145);
--color-tipex-success-800: oklch(0.39 0.15 145);
--color-tipex-success-900: oklch(0.33 0.12 145);
--color-tipex-success-950: oklch(0.21 0.08 145);
/* Premium Primary Colors (Purple/Violet) */
--color-tipex-primary-50: oklch(0.985 0.005 285);
--color-tipex-primary-100: oklch(0.972 0.01 285);
--color-tipex-primary-200: oklch(0.93 0.025 285);
--color-tipex-primary-300: oklch(0.875 0.05 285);
--color-tipex-primary-400: oklch(0.775 0.085 285);
--color-tipex-primary-500: oklch(0.65 0.11 285);
--color-tipex-primary-600: oklch(0.55 0.11 285);
--color-tipex-primary-700: oklch(0.47 0.095 285);
--color-tipex-primary-800: oklch(0.39 0.08 285);
--color-tipex-primary-900: oklch(0.33 0.065 285);
--color-tipex-primary-950: oklch(0.21 0.05 285);
/* Enhanced Spacing Scale */
--spacing-tipex-xs: 0.375rem;
--spacing-tipex-sm: 0.625rem;
--spacing-tipex-md: 1.125rem;
--spacing-tipex-lg: 1.75rem;
--spacing-tipex-xl: 2.25rem;
--spacing-tipex-2xl: 2.75rem;
/* Enhanced Sizing Scale */
--size-tipex-1: 0.375rem;
--size-tipex-2: 0.625rem;
--size-tipex-3: 0.875rem;
--size-tipex-4: 1.125rem;
--size-tipex-5: 1.375rem;
--size-tipex-6: 1.625rem;
--size-tipex-7: 1.875rem;
--size-tipex-8: 2.125rem;
--size-tipex-9: 2.375rem;
--size-tipex-10: 2.625rem;
--size-tipex-11: 2.875rem;
--size-tipex-12: 3.125rem;
/* Enhanced Border Radius */
--radius-tipex-sm: 0.375rem;
--radius-tipex-md: 0.5rem;
--radius-tipex-lg: 0.75rem;
/* Enhanced Typography */
--text-tipex-xs: 0.8125rem;
--text-tipex-sm: 0.9375rem;
--text-tipex-base: 1.0625rem;
--text-tipex-lg: 1.1875rem;
--text-tipex-xl: 1.375rem;
--text-tipex-2xl: 1.625rem;
/* Enhanced Z-Index */
--z-tipex-floating: 100;
--z-tipex-controls: 50;
/* Premium Shadows */
--shadow-tipex-sm: 0 1px 3px 0 rgb(0 0 0 / 0.08), 0 1px 2px 0 rgb(0 0 0 / 0.06);
--shadow-tipex-md: 0 4px 8px -2px rgb(0 0 0 / 0.12), 0 2px 4px -2px rgb(0 0 0 / 0.06);
--shadow-tipex-lg: 0 8px 16px -4px rgb(0 0 0 / 0.16), 0 4px 8px -4px rgb(0 0 0 / 0.08);
--shadow-tipex-focus: 0 0 0 3px oklch(0.65 0.11 285 / 0.4);
}
/* Custom Dark Mode Variant */
@custom-variant dark (&:where(.dark, .dark *));
/* Premium Component Styling */
@layer components {
.tipex-editor-premium {
@apply bg-gradient-to-br from-tipex-50 via-tipex-100 to-tipex-200
dark:from-tipex-950 dark:via-tipex-900 dark:to-tipex-800
border-2 border-tipex-200 dark:border-tipex-800
rounded-radius-tipex-lg shadow-tipex-md;
}
.tipex-editor-premium.focused.focal {
@apply shadow-tipex-focus
border-tipex-primary-500 dark:border-tipex-primary-400
outline-none ring-2 ring-tipex-primary-500/20 dark:ring-tipex-primary-400/20;
}
.tipex-control-premium {
@apply bg-tipex-100/90 dark:bg-tipex-900/90
backdrop-blur-sm border border-tipex-200/50 dark:border-tipex-800/50
rounded-radius-tipex-md shadow-tipex-sm;
}
.tipex-button-premium {
@apply px-spacing-tipex-md py-spacing-tipex-sm
bg-gradient-to-b from-tipex-100 to-tipex-200
dark:from-tipex-900 dark:to-tipex-800
border border-tipex-300 dark:border-tipex-700
rounded-radius-tipex-sm shadow-tipex-sm
hover:shadow-tipex-md hover:scale-105
active:scale-95 active:shadow-tipex-sm
transition-all duration-150 ease-out
focus:outline-none focus:ring-2 focus:ring-tipex-primary-500/40;
}
.tipex-button-premium.active {
@apply bg-gradient-to-b from-tipex-primary-100 to-tipex-primary-200
dark:from-tipex-primary-900 dark:to-tipex-primary-800
border-tipex-primary-500 dark:border-tipex-primary-400
text-tipex-primary-700 dark:text-tipex-primary-300
shadow-tipex-md ring-2 ring-tipex-primary-500/20 dark:ring-tipex-primary-400/20;
}
.tipex-scrollbar-premium {
scrollbar-width: thin;
scrollbar-color: oklch(0.65 0.11 285 / 0.3) transparent;
}
.tipex-scrollbar-premium::-webkit-scrollbar {
width: 6px;
}
.tipex-scrollbar-premium::-webkit-scrollbar-track {
background: transparent;
}
.tipex-scrollbar-premium::-webkit-scrollbar-thumb {
background: linear-gradient(to bottom,
oklch(0.65 0.11 285 / 0.3),
oklch(0.55 0.11 285 / 0.5));
border-radius: 3px;
}
.tipex-scrollbar-premium::-webkit-scrollbar-thumb:hover {
background: linear-gradient(to bottom,
oklch(0.65 0.11 285 / 0.5),
oklch(0.55 0.11 285 / 0.7));
}
.dark .tipex-scrollbar-premium {
scrollbar-color: oklch(0.65 0.11 285 / 0.4) transparent;
}
.dark .tipex-scrollbar-premium::-webkit-scrollbar-thumb {
background: linear-gradient(to bottom,
oklch(0.65 0.11 285 / 0.3),
oklch(0.55 0.11 285 / 0.5));
}
.dark .tipex-scrollbar-premium::-webkit-scrollbar-thumb:hover {
background: linear-gradient(to bottom,
oklch(0.65 0.11 285 / 0.5),
oklch(0.55 0.11 285 / 0.7));
}
} This example demonstrates Tailwind v4's powerful theming capabilities including gradient backgrounds, advanced shadows, custom scrollbars, and sophisticated component styling that would be much more complex in older Tailwind versions.
🚫 Why Tailwind v4 Only: Tipex exclusively supports and promotes Tailwind CSS v4 because it represents the future of utility-first CSS. The new architecture provides native CSS custom property integration, better performance, improved developer experience, and more maintainable code. We strongly discourage and do NOT support using older Tailwind versions (v1.x, v2.x, v3.x) as they lack the modern features that make Tipex's theming system possible.
⚠️ Legacy Tailwind Warning: Attempting to use Tipex with older Tailwind versions will result in broken styling, missing features, and poor performance. Upgrade to Tailwind v4 immediately.