> ## Documentation Index
> Fetch the complete documentation index at: https://docs.uniwind.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Custom Tailwind Utilities

> Add, extend, and override Tailwind utility classes using @utility and @theme in global.css

## Overview

Tailwind v4 lets you extend and override utilities directly in `global.css` using the `@utility` and `@theme` directives — no config file required. This guide covers three common scenarios:

1. **Variable-driven utilities** — create a utility whose value is injected at runtime via a CSS variable
2. **Brand-new utilities** — add a class that has no Tailwind equivalent
3. **Overriding existing utilities** — change what a built-in Tailwind class does

## Variable-Driven Utilities

Sometimes you need a utility class whose value isn't known until runtime. A common example is padding that accounts for a navigation header height, which is only available after the layout renders.

### Example: `p-safe-header`

**Step 1 — Declare the variable in `global.css`**

Use `@theme static` so the variable is always available in JavaScript even before it is updated, and define the utility with `@utility`:

```css global.css theme={null}
@import 'tailwindcss';
@import 'uniwind';

@theme static {
  --header-height: 0px;
}

@utility p-safe-header {
  padding-top: var(--header-height);
}
```

<Info>
  `@theme static` ensures `--header-height` is registered with Uniwind even if it is never used directly in a `className`. This is required for `updateCSSVariables` to pick it up.
</Info>

**Step 2 — Inject the real value at runtime**

Read the header height from react-navigation and push it into the CSS variable using `Uniwind.updateCSSVariables`:

```tsx theme={null}
import { useEffect } from 'react'
import { useNavigation } from '@react-navigation/native'
import { Uniwind } from 'uniwind'

export const useInjectHeaderHeight = () => {
  const navigation = useNavigation()

  useEffect(() => {
    const unsubscribe = navigation.addListener('layout', (e) => {
      const { height } = e.data.layout

      Uniwind.updateCSSVariables(Uniwind.currentTheme, {
        '--header-height': height,
      })
    })

    return unsubscribe
  }, [navigation])
}
```

**Step 3 — Use the utility**

```tsx theme={null}
import { View } from 'react-native'

export const Screen = () => (
  <View className="p-safe-header flex-1 bg-background">
    {/* content sits below the header */}
  </View>
)
```

## Brand-New Custom Utilities

Use `@utility` to define a class that doesn't exist in Tailwind at all. The CSS you write inside it maps directly to React Native style properties.

### Example: `card-shadow`

```css global.css theme={null}
@import 'tailwindcss';
@import 'uniwind';

@utility card-shadow {
  box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
}
```

Usage:

```tsx theme={null}
import { View, Text } from 'react-native'

export const Card = () => (
  <View className="card-shadow rounded-lg p-4 bg-white">
    <Text className="text-foreground text-base">Card content</Text>
  </View>
)
```

<Info>
  Custom utility names must be kebab-case. Tailwind scans your source files for them at build time, so the same [dynamic class name rules](/tailwind-basics#working-with-dynamic-classnames) apply — always write the full class name in source.
</Info>

## Overriding Existing Tailwind Utilities

### Override via `@theme` — change values only

The most common approach: keep the utility name but change what value it resolves to. This works for any design token in Tailwind's scale.

```css global.css theme={null}
@import 'tailwindcss';
@import 'uniwind';

@theme {
  /* p-4 now applies 20px instead of the default 16px */
  --spacing-4: 20px;

  /* rounded-lg now uses 16px instead of 8px */
  --radius-lg: 16px;
}
```

All utilities built on those tokens (`p-4`, `px-4`, `py-4`, `rounded-lg`, etc.) update automatically — no need to touch individual class definitions.

### Override via `@utility` — replace the generated CSS

Use `@utility` when you want to completely change what a class does, not just adjust its value.

**Example: make `border` always use `--color-primary`**

By default, `border` only sets `border-width` and `border-style`. Override it to also lock in the border color:

```css global.css theme={null}
@import 'tailwindcss';
@import 'uniwind';

@utility border {
  border-width: 1px;
  border-style: solid;
  border-color: var(--color-primary);
}
```

Now `border` always renders with the primary color instead of default value (black).

```tsx theme={null}
import { View } from 'react-native'

export const PrimaryBorderCard = () => (
  <View className="border rounded-lg p-4">
    {/* border is --color-primary */}
  </View>
)
```

## Real-World Example: Border Curve Utilities

iOS supports a `borderCurve` property that controls how border corners are rendered — `continuous` produces Apple's signature "squircle" shape, while `circular` is the standard round corner.

`border-continuous` and `border-circular` are built into Uniwind since `1.6.0` / `1.0.0-rc.6` (Pro):

```tsx theme={null}
import { View, Text } from 'react-native'

export const SquircleCard = () => (
  <View className="border-continuous rounded-2xl bg-white p-4">
    <Text className="text-foreground">iOS squircle corners</Text>
  </View>
)
```

<Info>
  On versions before `1.6.0` / `1.0.0-rc.6` (Pro), you need to add these utilities manually in your `global.css`:

  ```css global.css theme={null}
  @utility border-continuous {
    border-curve: continuous;
  }

  @utility border-circular {
    border-curve: circular;
  }
  ```

  This is a good example of how you can use `@utility` to expose any React Native style property as a Tailwind class.
</Info>

## Best Practices

<Tip>
  **Prefer `@theme` for value overrides.** It keeps the semantic class name and updates all related utilities in one place.
</Tip>

<Tip>
  **Use `@utility` for structural changes or new classes.** Reserve it for cases where the default CSS itself needs to change, not just its values.
</Tip>

<Warning>
  Only use CSS properties that React Native supports. Web-only properties like `background-image`, `display: grid`, or `position: fixed` have no effect on native.
</Warning>

## Related

<CardGroup cols={2}>
  <Card title="Global CSS" icon="css" href="/theming/global-css">
    Full reference for @theme, @utility, and global.css structure
  </Card>

  <Card title="updateCSSVariables" icon="code" href="/theming/update-css-variables">
    Inject CSS variable values at runtime
  </Card>

  <Card title="useCSSVariable" icon="code" href="/api/use-css-variable">
    Read CSS variable values in JavaScript
  </Card>
</CardGroup>
