Back to Home

Customization Guide

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.

Quick Customization Overview

Tipex offers multiple layers of customization:

  • Theme Customization: Colors, spacing, typography, and visual styling
  • Component Replacement: Replace built-in controls with your own components
  • Extension System: Add new functionality through TipTap extensions
  • Event Handling: Custom behavior through event listeners
  • Layout Customization: Header, footer, and utility area modifications

Theme & Styling 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 */
@import "tailwindcss";

@theme {
  /* Tipex Design System Override */
  --color-tipex-*: initial;
  
  /* Custom Primary Colors */
  --color-tipex-primary: #10b981; /* Custom green */
  --color-tipex-primary-dark: #34d399;
  
  /* Editor Colors */
  --color-tipex-editor-bg: #fafafa;
  --color-tipex-editor-bg-dark: #0f172a;
  --color-tipex-editor-text: #111827;
  --color-tipex-editor-text-dark: #f9fafb;
  
  /* Control Colors */
  --color-tipex-control-bg: #ffffff;
  --color-tipex-control-bg-dark: #1f2937;
  --color-tipex-control-hover: #f1f5f9;
  --color-tipex-control-hover-dark: #374151;
  --color-tipex-control-active: #dcfce7;
  --color-tipex-control-active-dark: #1e3a8a;
  
  /* Typography Scale */
  --text-tipex-base: 1.125rem;
  --text-tipex-lg: 1.25rem;
  --text-tipex-xl: 1.5rem;
  
  /* Spacing Scale */
  --spacing-tipex-xs: 0.25rem;
  --spacing-tipex-sm: 0.5rem;
  --spacing-tipex-md: 1rem;
  --spacing-tipex-lg: 1.5rem;
  --spacing-tipex-xl: 2rem;
  
  /* Border Radius */
  --radius-tipex-sm: 0.25rem;
  --radius-tipex-md: 0.375rem;
  --radius-tipex-lg: 0.5rem;
  
  /* Shadows */
  --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(16 185 129 / 0.5);
  --shadow-tipex-focus-dark: 0 0 0 3px rgb(52 211 153 / 0.5);
}

/* Custom Dark Mode Variant (Tailwind v4) */
@custom-variant dark (&:where(.dark, .dark *));

/* Component Layer Customization */
@layer components {
  .tipex-editor {
    @apply bg-tipex-editor-bg dark:bg-tipex-editor-bg-dark 
           border-tipex-editor-border dark:border-tipex-editor-border-dark
           rounded-tipex-md;
  }
  
  .tipex-editor.focused.focal {
    @apply shadow-tipex-focus dark:shadow-tipex-focus-dark
           border-transparent outline-none;
  }
  
  .custom-editor-theme {
    @apply bg-gradient-to-br from-tipex-editor-bg to-tipex-control-bg
           dark:from-tipex-editor-bg-dark dark:to-tipex-control-bg-dark;
  }
}

Built-in Utility Components

The built-in utility section includes essential tools like copy functionality and link management. You can easily integrate these or add your own custom utilities.

Tipex Editor utility buttons location and customization options
Utility buttons provide quick access to common editor functions

Adding Built-in Utilities

Include the default utility buttons (copy, link management) in your editor:

import {Utility} from "@friendofsvelte/tipex";
<Tipex body={body}>
  {#snippet utilities(tipex)}
    <Utility {tipex}/>
  {/snippet}
</Tipex>

Custom Utility Integration

Extend the utility area with your own custom buttons and functionality:

<Tipex body={body}>
 {#snippet utilities(tipex)}
   <div aria-label="Custom utility button">...</div>
 {/snippet}
</Tipex>

Here's a more comprehensive example with multiple custom utilities:

<Tipex body={body}>
  {#snippet utilities(tipex)}
    <!-- Built-in utilities -->
    <Utility {tipex}/>
    
    <!-- Custom utilities -->
    <button 
      class="tipex-edit-button tipex-button-rigid"
      onclick={() => exportToPDF(tipex.getHTML())}
      aria-label="Export to PDF"
    >
      <iconify-icon icon="fa6-solid:file-pdf"></iconify-icon>
    </button>
    
    <button 
      class="tipex-edit-button tipex-button-rigid"
      onclick={() => insertTemplate(tipex)}
      aria-label="Insert template"
    >
      <iconify-icon icon="fa6-solid:file-contract"></iconify-icon>
    </button>
    
    <button 
      class="tipex-edit-button tipex-button-rigid"
      onclick={() => toggleFullscreen()}
      aria-label="Toggle fullscreen"
    >
      <iconify-icon icon="fa6-solid:expand"></iconify-icon>
    </button>
  {/snippet}
</Tipex>

Tipex Props

Prop NameDefaultConditionDescription
head(tipex)undefinedOptionalA slot that accepts a function receiving the TipexEditor instance, rendered above the main editor content area
controlComponentSnippet<[TipexEditor]>Only used when you want to replace default controls entirely
utilitiesSnippet<[TipexEditor]>Only used when you want to customize the default controls toolbar
foot(tipex)undefinedOptionalA slot that accepts a function receiving the TipexEditor instance, rendered below the editor content and controls

Control System

Tipex automatically detects which control system to use:

  • When controlComponent is provided: Uses your custom control component
  • When controlComponent is not provided: Shows default controls with optional utilities

This ensures a clean API where you don't need to manage boolean flags.

Complete Control Replacement

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-tipex-md p-tipex-lg
	  bg-tipex-control-bg dark:bg-tipex-control-bg-dark
      rounded-tipex-md shadow-tipex-sm
      border border-tipex-control-border dark:border-tipex-control-border-dark;
    }
</style>

⚠️ Tailwind v4 ONLY - No Legacy Versions!

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.

Legacy Tailwind Versions Not Supported

  • Tailwind v3.x and older lack @theme configuration
  • Missing @custom-variant syntax for advanced dark mode
  • Inferior performance and larger bundle sizes
  • Limited component layer organization

Tailwind v4 Advantages

Tipex exclusively uses Tailwind CSS v4 for superior developer experience and performance:

  • 🚀 Modern Import System: Clean `@import "tailwindcss"` syntax without configuration files
  • 🎨 Native CSS Custom Properties: Direct integration with CSS variables in `@theme` blocks
  • ⚡ Better Performance: Faster builds and smaller bundle sizes compared to v3.x
  • 🛠️ Enhanced DX: Improved IntelliSense and better error messages
  • 🌙 Custom Variants: Powerful `@custom-variant` syntax for complex state handling
  • 📦 Component Layers: Better organization with `@layer components` for maintainable styles
  • 🔮 Future-Proof: Built for modern CSS features and browser capabilities

Tailwind v4 Required

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.

Advanced Layout Customization

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>

Image Upload Customization

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 utilities(tipex)}
    <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"
    >
      <iconify-icon icon="fa6-solid:image"></iconify-icon>
    </button>
  {/snippet}
</Tipex>

Extension System

Leverage TipTap's powerful extension system to add custom functionality. Tipex provides easy access to modify and extend the editor's capabilities:

Advanced customization example showing custom extensions and theming in Tipex Editor
Advanced customization with custom extensions and theming. View Source Code

Modifying Default Extensions

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} />

Creating Custom Extensions

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"
      >
        <iconify-icon icon="fa6-solid:highlighter"></iconify-icon>
      </button>
      
      <!-- Word count display -->
      <span class="word-count">
        Words: {tipex.storage.wordCount?.wordCount || 0}
      </span>
    </div>
  {/snippet}
</Tipex>

Event-Driven Customization

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>

Accessibility Customization

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>

Performance Optimization with Tailwind v4

Optimize your customized editor using Tailwind v4's performance benefits:

  • 🎯 Tailwind v4 Tree Shaking: Automatic unused CSS elimination
  • ⚡ Faster Builds: Improved build performance over legacy versions
  • 📦 Smaller Bundles: More efficient CSS generation
  • 🔄 Lazy Loading: Load extensions and components only when needed
  • ⏱️ Debounced Updates: Throttle auto-save and real-time features
  • 🖥️ Virtual Scrolling: For large documents, implement virtual scrolling
  • 🧠 Memory Management: Clean up event listeners and subscriptions

Tailwind v4 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.

Advanced Tailwind v4 Theming

Create sophisticated themes using Tailwind v4's advanced features. Here's a complete example of a premium theme configuration:

/* Custom Tipex Theme with Tailwind v4 */
@import "tailwindcss";

@theme {
  /* Custom Tipex Design System */
  --color-tipex-*: initial;
  
  /* Brand Colors */
  --color-tipex-primary: #8b5cf6; /* Purple brand */
  --color-tipex-primary-dark: #a78bfa;
  --color-tipex-secondary: #64748b;
  --color-tipex-secondary-dark: #94a3b8;
  
  /* Custom Editor Theme */
  --color-tipex-editor-bg: #fefefe;
  --color-tipex-editor-bg-dark: #0c0a09;
  --color-tipex-editor-border: #e2e8f0;
  --color-tipex-editor-border-dark: #292524;
  --color-tipex-editor-text: #0f172a;
  --color-tipex-editor-text-dark: #fafaf9;
  
  /* Premium Control Colors */
  --color-tipex-control-bg: #ffffff;
  --color-tipex-control-bg-dark: #1c1917;
  --color-tipex-control-hover: #f8fafc;
  --color-tipex-control-hover-dark: #292524;
  --color-tipex-control-active: #ede9fe;
  --color-tipex-control-active-dark: #581c87;
  --color-tipex-control-border: #cbd5e1;
  --color-tipex-control-border-dark: #44403c;
  
  /* 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;
  
  /* Custom Spacing */
  --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;
  
  /* Modern Shadows */
  --shadow-tipex-sm: 0 1px 3px 0 rgb(0 0 0 / 0.08);
  --shadow-tipex-md: 0 4px 8px -2px rgb(0 0 0 / 0.12);
  --shadow-tipex-lg: 0 8px 16px -4px rgb(0 0 0 / 0.16);
  --shadow-tipex-focus: 0 0 0 3px rgb(139 92 246 / 0.4);
  --shadow-tipex-focus-dark: 0 0 0 3px rgb(167 139 250 / 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-editor-bg via-white to-tipex-control-bg
           dark:from-tipex-editor-bg-dark dark:via-stone-900 dark:to-tipex-control-bg-dark
           border-2 border-tipex-editor-border dark:border-tipex-editor-border-dark
           rounded-tipex-lg shadow-tipex-md;
  }
  
  .tipex-editor-premium.focused.focal {
    @apply shadow-tipex-focus dark:shadow-tipex-focus-dark
           border-tipex-primary dark:border-tipex-primary-dark
           outline-none ring-2 ring-tipex-primary/20 dark:ring-tipex-primary-dark/20;
  }
  
  .tipex-control-premium {
    @apply bg-tipex-control-bg/90 dark:bg-tipex-control-bg-dark/90
           backdrop-blur-sm border border-tipex-control-border/50 dark:border-tipex-control-border-dark/50
           rounded-tipex-md shadow-tipex-sm;
  }
  
  .tipex-button-premium {
    @apply px-tipex-md py-tipex-sm
           bg-gradient-to-b from-tipex-control-bg to-tipex-control-hover
           dark:from-tipex-control-bg-dark dark:to-tipex-control-hover-dark
           border border-tipex-control-border dark:border-tipex-control-border-dark
           rounded-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/40;
  }
  
  .tipex-button-premium.active {
    @apply bg-gradient-to-b from-tipex-control-active to-tipex-primary/10
           dark:from-tipex-control-active-dark dark:to-tipex-primary-dark/10
           border-tipex-primary dark:border-tipex-primary-dark
           text-tipex-primary dark:text-tipex-primary-dark
           shadow-tipex-md ring-2 ring-tipex-primary/20 dark:ring-tipex-primary-dark/20;
  }
  
  .tipex-scrollbar-premium {
    scrollbar-width: thin;
    scrollbar-color: rgb(139 92 246 / 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, rgb(139 92 246 / 0.3), rgb(139 92 246 / 0.5));
    border-radius: 3px;
  }
  
  .tipex-scrollbar-premium::-webkit-scrollbar-thumb:hover {
    background: linear-gradient(to bottom, rgb(139 92 246 / 0.5), rgb(139 92 246 / 0.7));
  }
  
  .dark .tipex-scrollbar-premium {
    scrollbar-color: rgb(167 139 250 / 0.4) transparent;
  }
  
  .dark .tipex-scrollbar-premium::-webkit-scrollbar-thumb {
    background: linear-gradient(to bottom, rgb(167 139 250 / 0.3), rgb(167 139 250 / 0.5));
  }
  
  .dark .tipex-scrollbar-premium::-webkit-scrollbar-thumb:hover {
    background: linear-gradient(to bottom, rgb(167 139 250 / 0.5), rgb(167 139 250 / 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.