Theming

Choose from a variety of pre-styled themes or develop your own in FishtVue.

Architecture

FishtVue is a design-agnostic library, so unlike some other UI libraries, it does not enforce a certain styling such as material design. Styling is decoupled from the components using the themes instead. A theme consists of two parts: base and preset. The base is the style rules with CSS variables as placeholders, whereas the preset is a set of design tokens to feed a base by mapping the tokens to CSS variables. A base may be configured with different presets.

Design Tokens

The core of the styled mode architecture is based on a concept named design token. A preset defines the token configuration in three tiers: primitive, semantic, and component.

Primitive Tokens

Primitive tokens have no context. A color palette, such as blue-50 to blue-900, is a good example of a primitive token. A token named blue-500 may be used as the primary color or the background of a message, but on its own, the name of the token does not indicate context. Usually, they are utilized by the semantic tokens.

Semantic Tokens

Semantic tokens define content, and their names indicate where they are utilized. A well-known example of a semantic token is primary.color. Semantic tokens map to primitive tokens or other semantic tokens. The colorScheme token group is a special variable to define tokens based on the color scheme active in the application, allowing different tokens based on the color scheme, like dark mode.

Component Tokens

Component tokens are isolated tokens per component, such as inputtext.background or button.color, that map to the semantic tokens. For example, the button.background component token maps to the primary.color semantic token, which maps to the green.500 primitive token.

Best Practices

  • Use primitive tokens when defining the core color palette.
  • Use semantic tokens to specify common design elements such as focus ring, primary colors, and surfaces.
  • Use component tokens when customizing a specific component.

By defining your own design tokens as a custom preset, you'll be able to define your own style without touching CSS. Overriding the FishtVue components using style classes is not a best practice and should be the last resort; design tokens are the suggested approach.

Options Theme

The optionsTheme property allows you to configure global theming behavior in FishtVue. It supports setting a theme name, custom CSS variable prefixes, dark/light mode selectors, and advanced options like CSS layering and minification control.

Basic Usage

main.ts
import FishtVue from 'fishtvue/config';

app.use(FishtVue, {
  optionsTheme: {
    nameTheme: "Aurora",
    prefix: "fishtvue",
    layers: "layer",
    isNotMinifyCSS: true,
    lightModeSelector: "html.light",
    darkModeSelector: "html.dark",
  },
});

nameTheme

The nameTheme option lets you choose which built-in theme preset to use. You can pick from "Aurora", "Harmony", or "Sapphire", depending on the visual style you want for your app. By default, it uses "Aurora". This setting is especially helpful if you're planning to switch between different design systems or need a consistent theme across multiple projects.

main.ts
optionsTheme: {
  nameTheme: "Aurora"
}

prefix

The prefix option lets you define a custom prefix for all CSS variables generated by the theme. By default, it's set to "fishtvue".

main.ts
optionsTheme: {
  prefix: "fishtvue"
}

lightModeSelector

The lightModeSelector option lets you set a custom CSS selector to control when light mode styles should apply. By default, light mode is always active (so the value is just an empty string). This option becomes useful if you’re manually toggling between light and dark modes and want more control over how light mode is applied.

main.ts
optionsTheme: {
  lightModeSelector: "html.light"
}

darkModeSelector

The darkModeSelector option lets you specify a CSS selector that will trigger dark mode styles. For example, you might use "html.dark" or ".dark-mode" if you’re toggling dark mode in your app manually. If you don’t set anything, the system preference will be used by default. You can also disable dark mode entirely by setting this option to false.

main.ts
optionsTheme: {
  darkModeSelector: "html.dark"
}

Example: Toggle Dark Mode

index.html
<button @click="toggleDarkMode">Toggle Dark Mode</button>

script.js
function toggleDarkMode() {
  document.documentElement.classList.toggle('dark');
}

To completely disable dark mode support:

optionsTheme: {
  darkModeSelector: false
}

layers

The layers option allows you to wrap the generated CSS in a custom CSS cascade layer. This helps manage style priority and makes it easier to integrate with other frameworks. You can use the built-in "fishtvue" layer or define your own. By default, no layer is applied unless you explicitly set this option.

optionsTheme: {
  layers: "fishtvue"
}

Or define custom cascade order:

optionsTheme: {
  layers: "base, fishtvue, overrides"
}

isNotMinifyCSS

The isNotMinifyCSS option controls whether the generated CSS should be minified. By default, it's set to false, meaning the CSS will be minified for better performance. If you set it to true, minification will be disabled, which can make the output easier to read and debug during development.

optionsTheme: {
  isNotMinifyCSS: true
}

Built-in Presets

FishtVue includes several theme presets designed to suit various design philosophies:

  • Aurora – Default preset, vibrant and modern
  • Harmony – Minimalistic and soft
  • Sapphire – Enterprise-focused design

These presets can be extended or used as references for building your own custom design system.

Tips

  • Combine prefix and layers to namespace and organize your CSS properly.
  • Use darkModeSelector and lightModeSelector to support user-controlled themes.
  • Disable isNotMinifyCSS in production for optimal performance.

Utils

usePreset

Replaces the current presets entirely. A common use case is changing the preset dynamically at runtime.

import { usePreset } from '@fishtvue/themes';

const onButtonClick() {
    usePreset(MyPreset);
}

updatePreset

Merges the provided tokens to the current preset. An example would be changing the primary color palette dynamically.

import { updatePreset } from '@fishtvue/themes';

const changePrimaryColor() {
    updatePreset({
        semantic: {
            primary: {
                50: '{indigo.50}',
                100: '{indigo.100}',
                200: '{indigo.200}',
                300: '{indigo.300}',
                400: '{indigo.400}',
                500: '{indigo.500}',
                600: '{indigo.600}',
                700: '{indigo.700}',
                800: '{indigo.800}',
                900: '{indigo.900}',
                950: '{indigo.950}'
            }
        }
    });
}

updatePrimaryPalette

Updates the primary colors. This is a shorthand to do the same update using updatePreset.

import { updatePrimaryPalette } from '@fishtvue/themes';

const changePrimaryColor() {
    updatePrimaryPalette({
        50: '{indigo.50}',
        100: '{indigo.100}',
        200: '{indigo.200}',
        300: '{indigo.300}',
        400: '{indigo.400}',
        500: '{indigo.500}',
        600: '{indigo.600}',
        700: '{indigo.700}',
        800: '{indigo.800}',
        900: '{indigo.900}',
        950: '{indigo.950}'
    });
}

updateSurfacePalette

Updates the surface colors. This is a shorthand to do the same update using updatePreset.

import { updateSurfacePalette } from '@fishtvue/themes';

const changeSurfaces() {
    // Changes surfaces both in light and dark mode
    updateSurfacePalette({
        50: '{zinc.50}',
        // ...
        950: '{zinc.950}'
    });
}

const changeLightSurfaces() {
    // Changes surfaces only in light mode
    updateSurfacePalette({
        light: {
            50: '{zinc.50}',
            // ...
            950: '{zinc.950}'
        }
    });
}

const changeDarkSurfaces() {
    // Changes surfaces only in dark mode
    updateSurfacePalette({
        dark: {
            50: '{zinc.50}',
            // ...
            950: '{zinc.950}'
        }
    });
}

$dt

The $dt function returns the information about a token like the full path and value. This is useful if you need to access tokens programmatically.

import { $dt } from '@fishtvue/themes';

const duration = $dt('transition.duration');
/*
    duration: {
        name: '--transition-duration',
        variable: 'var(--p-transition-duration)',
        value: '0.2s'
    }
*/

const primaryColor = $dt('primary.color');
/*
    primaryColor: {
        name: '--primary-color',
        variable: 'var(--p-primary-color)',
        value: {
            light: {
                value: '#10b981',
                paths: {
                    name: 'semantic.primary.color',
                    binding: {
                        name: 'primitive.emerald.500'
                    }
                }
            }
        },
        dark: {
            value: '#34d399',
            paths: {
                name: 'semantic.primary.color',
                binding: {
                    name: 'primitive.emerald.400'
                }
            }
        }
    }
}
*/

palette

Returns shades and tints of a given color from 50 to 950 as an object.

import { palette } from '@fishtvue/themes';

// Custom color
const values1 = palette('#10b981');

// Copy an existing token set
const primaryColor = palette('{blue}');
© 2025 FishtVue by Egoka