# Pressable example

> Press feedback in React, Vue, Angular, Svelte, and Solid.

`pressable` shares the same press state machine across every adapter, and on all
five it is a bare host tag — there is no component body to call a children render
function, so `pressed` never arrives that way. Every adapter mirrors it into its
own local state off `onPressIn`/`onPressOut` instead. Angular's press events are a
real `@Output()`.

<Tabs syncKey="framework">
  <TabItem label="React">
    ```tsx
    import './Pressable.css';

    import { useState } from 'react';

    export function PressableLabel() {
      const [pressed, setPressed] = useState(false);

      return (
        <pressable
          onPress={() => console.log('pressed')}
          onPressIn={() => setPressed(true)}
          onPressOut={() => setPressed(false)}
        >
          <text className={pressed ? 'down' : 'up'}>{pressed ? 'Release' : 'Press me'}</text>
        </pressable>
      );
    }
    ```

    ```css
    /* Pressable.css */
    .up { opacity: 1; }
    .down { opacity: 0.55; }
    ```

  </TabItem>
  <TabItem label="Vue">
    ```vue
    <script setup lang="ts">
    import { ref } from 'vue';

    const pressed = ref(false);
    </script>

    <template>
      <pressable
        @press="console.log('pressed')"
        @press-in="pressed = true"
        @press-out="pressed = false"
      >
        <text :class="pressed ? 'down' : 'up'">
          {{ pressed ? 'Release' : 'Press me' }}
        </text>
      </pressable>
    </template>

    <style scoped>
    .up { opacity: 1; }
    .down { opacity: 0.55; }
    </style>
    ```

  </TabItem>
  <TabItem label="Angular">
    ```ts
    import { Component } from '@angular/core';
    import { SYMBIOTE_ELEMENTS } from '@symbiote-native/angular';
    import './pressable.css';

    @Component({
      standalone: true,
      imports: [SYMBIOTE_ELEMENTS],
      template: `
        <pressable
          (press)="onPress()"
          (pressIn)="pressed = true"
          (pressOut)="pressed = false"
          [class]="pressed ? 'down' : 'up'"
        >
          <text>{{ pressed ? 'Release' : 'Press me' }}</text>
        </pressable>
      `,
    })
    export class PressableLabel {
      pressed = false;

      onPress(): void {
        console.log('pressed');
      }
    }
    ```

    ```css
    /* pressable.css */
    .up { opacity: 1; }
    .down { opacity: 0.55; }
    ```

  </TabItem>
  <TabItem label="Svelte">
    ```svelte
    <script lang="ts">
      let pressed = $state(false);
    </script>

    <!-- Event handlers on a bare host tag go through the `p={{ … }}` bag — an
         individual `on*` attribute is silently misrouted through Svelte's own
         DOM event system instead of the engine. -->
    <pressable
      p={{
        onPress: () => console.log('pressed'),
        onPressIn: () => (pressed = true),
        onPressOut: () => (pressed = false),
      }}
    >
      <text class={pressed ? 'down' : 'up'}>{pressed ? 'Release' : 'Press me'}</text>
    </pressable>

    <style>
      .up { opacity: 1; }
      .down { opacity: 0.55; }
    </style>
    ```

  </TabItem>
  <TabItem label="Solid">
    ```tsx
    import './Pressable.css';
    import { createSignal } from 'solid-js';

    export function PressableLabel() {
      const [pressed, setPressed] = createSignal(false);

      return (
        <pressable
          onPress={() => console.log('pressed')}
          onPressIn={() => setPressed(true)}
          onPressOut={() => setPressed(false)}
        >
          <text class={pressed() ? 'down' : 'up'}>
            {pressed() ? 'Release' : 'Press me'}
          </text>
        </pressable>
      );
    }
    ```

    ```css
    /* Pressable.css */
    .up { opacity: 1; }
    .down { opacity: 0.55; }
    ```

  </TabItem>
</Tabs>

## API takeaway

React is the only adapter where `pressable` still exposes state through a
children render function, `children: (state) => ReactNode`. The `pressable`
tag on Vue, Angular, Svelte, and Solid has no render-prop channel
for its children, so each one instead reads `onPressIn`/`onPressOut`
directly and mirrors `pressed` into its own local reactive state, then derives
a class or style from that: Vue's `@press-in`/`@press-out`, Angular's
`(pressIn)`/`(pressOut)` `@Output()`s, Solid's `onPressIn`/`onPressOut` props
setting a signal, and Svelte's `onPressIn`/`onPressOut` inside the `p={{ … }}`
bag every event handler on a bare host tag needs. All five still read from the
same shared press state machine underneath. `StyleSheet.create` works
identically to a CSS class if you'd rather keep style objects inline — see the
[Styling guide](/docs/learn/styling/).
