Composables logo

Composables

Organization
PatternsDev
composables

Teaches Vue composables for reusable stateful logic with the Composition API. Use when extracting shared reactive state, side effects, or computed logic that multiple components need.

Overview

PublisherPatternsDev
Repositoryskills
Skill namecomposables
Stars
250
Forks
27
Bundled files
Instructions only
LicenseMIT
Links
  • Markdown instructions

    A SKILL.md file the model loads on demand, so it only costs tokens when a request actually matches.

  • Works with any LLM

    AI skills are plain Markdown, not provider-specific code, so this works with GPT, Claude, Gemini, Grok, or a local model.

  • Self-contained

    Everything the model needs lives in the instructions — no extra files to sync.

  • Open source

    Published by PatternsDev on GitHub. Read the source before you install it.

Installation

Install the Composables AI skill in TypingMind to use it with any LLM, or drop it into another agent that reads SKILL.md.

1

Install in TypingMind

TypingMind installs a skill straight from its GitHub folder — it reads SKILL.md, bundles the resource files, and stores the result locally.

  1. Open the app and go to Plugins → Skills.
  2. Choose "Install from GitHub".
  3. Paste the skill folder URL below and confirm.
  4. Enable the skill in any chat where you want it available.
Plugins → Skills → Add skill → From GitHub URL, then paste the folder URL and press Continue.
2

Install in another agent

Any agent that reads the Agent Skills format can use this skill — copy the folder into that agent's skills directory.

Claude Code — .claude/skills
git clone --depth 1 https://github.com/PatternsDev/skills.git /tmp/skills
mkdir -p .claude/skills
cp -r /tmp/skills/vue/composables .claude/skills/composables
Restart Claude Code after copying so it picks up the new skill.

Use it in TypingMind

Enable Composables in any TypingMind chat and the model takes it from there. Its name and description sit in the system prompt, and the moment a request matches, the model loads the full instructions itself — you never invoke it by hand, and it costs no tokens until it is actually used.

The model loads Composables on its own as soon as a request matches it.

Works with any AI model

AI skills are plain Markdown instructions rather than provider-specific code, so Composables is not tied to the model it was written for. Install it once in TypingMind and use it with GPT-5, Claude, Gemini, Grok, DeepSeek, Mistral, Llama, or a local model you run yourself — all on your own API keys.

  • Loaded only when it is needed

    The system prompt carries just the name and description. The instructions are fetched on the first matching request, so an idle skill costs nothing.

  • Switch models mid-chat

    Because the skill is instructions rather than code, changing model does not break it — the next model reads the same SKILL.md.

Skill instructions

This is the SKILL.md content the model loads. Read it before installing — a skill is instructions your model will follow.

Composables

Table of Contents

Composables are functions that encapsulate and reuse stateful logic using Vue's Composition API. They replace the Options API's fragmented code organization with clean, composable functions that can be shared across components.

When to Use

  • Use this when you need to share stateful logic across multiple components without duplication
  • This is helpful for extracting concerns like data fetching, event listeners, or timers into reusable functions

Instructions

  • Name composable functions with the use prefix by convention (e.g., useCounter, useWidth)
  • Use ref(), reactive(), and lifecycle hooks (onMounted, onBeforeUnmount) inside composables
  • Return reactive state and methods from composables for use in component templates
  • Prefer composables over the Options API for better code organization, reusability, and TypeScript support

Details

Options API

Before the introduction of the Composition API in Vue, developers relied on the Options API to organize component logic which include reactive data, lifecycle methods, computed properties, and more. The Options API allowed defining these aspects within specific options, as shown in the example below:

html
<!-- Template -->

<script>
  export default {
    name: "MyComponent",
    props: {
      // props
    },
    data() {
      // data
    },
    computed: {
      // computed properties
    },
    watch: {
      // properties to watch
    },
    methods: {
      // methods
    },
    created() {
      // lifecyle methods like created
    },
    // ...
  };
</script>

<!-- Styles -->

While this approach served its purpose and is still applicable in Vue v3, it can become challenging to manage and maintain as components grow larger and more complex. Defining component logic within specific options can make it harder to read and understand the code, especially when dealing with extensive components. Extracting and reusing common logic between components can also be difficult in this setup.

Let's take a look at a simple example of an App component that renders two individual child components — Count and Width.

html
<template>
  <div class="App">
    <Count :count="count" :increment="increment" :decrement="decrement" />
    <div id="divider" />
    <Width :width="width" />
  </div>
</template>

<script>
  import Count from "./components/Count.vue";
  import Width from "./components/Width.vue";

  export default {
    name: "App",
    data() {
      return {
        count: 0,
        width: 0,
      };
    },
    mounted() {
      this.handleResize();
      window.addEventListener("resize", this.handleResize);
    },
    beforeUnmount() {
      window.removeEventListener("resize", this.handleResize);
    },
    methods: {
      increment() {
        this.count++;
      },
      decrement() {
        this.count--;
      },
      handleResize() {
        this.width = window.innerWidth;
      },
    },
    components: {
      Count,
      Width,
    },
  };
</script>

The code snippet above represents a Vue single-file component (SFC) named App.

The <template> section defines the markup of the component. In this case, it contains a <div> element with the class "App" that wraps two child components: <Count> and <Width>. These child components are passed certain properties using Vue's attribute binding syntax (:count, :increment, :decrement, and :width).

The <script> section contains the JavaScript code for the component. Within the component definition, we have:

  • The data method which returns an object containing the initial data properties of the component, which are count and width initialized to 0.
  • The mounted() lifecycle hook is used to execute code after the component has been mounted in the DOM. In this case, it calls the handleResize() method and adds an event listener for the resize event.
  • The beforeUnmount() lifecycle hook is used to execute code before the component is unmounted and destroyed. Here, it removes the event listener for the resize event.
  • The methods object contains the component's methods. It defines increment(), decrement(), and handleResize() methods that manipulate the count and width data properties based on certain events or actions.

When the app is run, the current count and the window's inner width are displayed in real-time. The user can interact with the component by incrementing and decrementing the count using the buttons in the <Count> component. Similarly, the width is automatically updated whenever the window is resized.

Even though this component is small in size, the logic inside it is already intertwined. Some parts are dedicated to the functionality of the counter, while others pertain to the width logic. As the component grows, organizing and locating related logic within the component would become more challenging.

To address these challenges, the Vue team introduced the Composition API in Vue v3.

Composition API

The Composition API can be seen as an API that provides standalone functions representing Vue's core capabilities. These functions are primarily used within a single setup() option which serves as the entry point for utilizing the Composition API.

html
<!-- Template -->

<script>
  export default {
    name: "MyComponent",
    setup() {
      // the setup function
    },
  };
</script>

<!-- Styles -->

The setup() function is executed before a component is created and when the props of the component are available.

With the Composition API, we can import standalone functions to help us access Vue's core capabilities within our component. Let's rewrite the counter and width example we've seen above while relying on the Composition API syntax.

html
<template>
  <div class="App">
    <Count :count="count" :increment="increment" :decrement="decrement" />
    <div id="divider" />
    <Width :width="width" />
  </div>
</template>

<script>
  import { ref, onMounted, onBeforeUnmount } from "vue";
  import Count from "./components/Count.vue";
  import Width from "./components/Width.vue";

  export default {
    name: "App",
    setup() {
      const count = ref(0);
      const width = ref(0);

      const increment = () => {
        count.value++;
      };

      const decrement = () => {
        count.value--;
      };

      const handleResize = () => {
        width.value = window.innerWidth;
      };

      onMounted(() => {
        handleResize();
        window.addEventListener("resize", handleResize);
      });

      onBeforeUnmount(() => {
        window.removeEventListener("resize", handleResize);
      });

      return {
        count,
        width,
        increment,
        decrement,
      };
    },
    components: {
      Count,
      Width,
    },
  };
</script>

The <template> of our component remains the same but in the <script> section of our component, we now utilize the Composition API with the setup() function.

Inside the setup() function, we:

  • Define the count and width reactive variables using the ref() function — the function that accepts a single primitive value (e.g. string, number, etc.) and returns a reactive/mutable object.
  • We also define the custom functions increment(), decrement(), and handleResize(). These functions are similar to the methods we defined in our previous Options API example.
  • We use the onMounted() lifecycle function to call the custom handleResize() function and add an event listener for the resize event when the component is mounted. Similarly, we use the onBeforeUnmount() lifecycle function to remove the event listener for the resize event before the component is unmounted.
  • The reactive variables and functions defined in the setup() function are then returned, making them accessible in the component template.

Composables

With our previous code example, one might still wonder how the setup() function offers any advantage to development since it appears that it just requires us to declare component options within a single function.

One of the fantastic benefits of adopting the composition API is the capability to extract and reuse shared logic between components. This is driven by the fact that we can simply declare functions of our own that use Vue's globally available composition functions and have our functions be easily used in multiple components to achieve the same outcome.

Let's take our previous counter and width example further by creating composable functions that encapsulates shared logic that can be reused across components.

First, let's create a composable function called useCounter, a composable that encapsulates the counter functionality and returns the current value of count, an increment() method, and a decrement() method.

By convention, composable function names start with the "use" keyword.

js
import { ref } from "vue";

export function useCounter(initialCount = 0) {
  const count = ref(initialCount);

  function increment() {
    count.value++;
  }

  function decrement() {
    count.value--;
  }

  return {
    count,
    increment,
    decrement,
  };
}

Similarly, we can create a composable called useWidth() that encapsulates the width functionality of our app.

js
import { ref, onMounted, onBeforeUnmount } from "vue";

export function useWidth() {
  const width = ref(0);

  function handleResize() {
    width.value = window.innerWidth;
  }

  onMounted(() => {
    handleResize();
    window.addEventListener("resize", handleResize);
  });

  onBeforeUnmount(() => {
    window.removeEventListener("resize", handleResize);
  });

  return {
    width,
  };
}

In our App component, we can now use the composable functions to achieve the same outcome:

html
<template>
  <div class="App">
    <Count :count="count" :increment="increment" :decrement="decrement" />
    <div id="divider" />
    <Width :width="width" />
  </div>
</template>

<script>
  import Count from "./components/Count.vue";
  import Width from "./components/Width.vue";
  import { useCounter } from "./composables/useCounter";
  import { useWidth } from "./composables/useWidth";

  export default {
    name: "App",
    components: {
      Count,
      Width,
    },
    setup() {
      const { count, increment, decrement } = useCounter(0);
      const { width } = useWidth();

      return {
        count,
        increment,
        decrement,
        width,
      };
    },
  };
</script>

With these changes, our app will function the same as it did before but in a more composable setting.

By using composable functions in the Composition API setting, we were able to break the context of our app down into smaller, reusable pieces that separated the logic.

Using composable functions in Vue made it easier to separate the logic of our component into several smaller pieces. Reusing the same stateful logic now becomes easy since we are no longer confined to organizing our code within specific options in the Options API.

With composable functions, we have the flexibility to extract and reuse shared logic across components. This separation of concerns allows us to focus on specific functionality within each composable function making our code more modular and maintainable.

By breaking down the logic into smaller, reusable pieces, we can compose our components using these composable functions, bringing together the necessary functionality without duplicating code. This approach promotes code reusability and reduces the risk of code duplication and inconsistencies.

Additionally, using the Composition API provides better readability and understandability of the component's logic. Each composable function encapsulates a specific aspect of the component's behavior, making it easier to reason about and test. It also allows for easier collaboration among team members, as the code becomes more structured and organized.

Lastly, building Vue apps with the Composition API allows for better type inference. Since the Composition API helps us handle our component logic with variables and standard JavaScript functions, it becomes a lot easier to build large-scale Vue applications with a static type system like TypeScript!

Source

References

Frequently asked questions

What does the Composables AI skill do?

Teaches Vue composables for reusable stateful logic with the Composition API. Use when extracting shared reactive state, side effects, or computed logic that multiple components need.

Why use Composables on TypingMind?

Because you install it once and use it with any model. Composables is plain Markdown rather than provider-specific code, so the same skill runs on GPT-5, Claude, Gemini, Grok, or a local model — and you can switch model mid-chat without it breaking. TypingMind runs on your own API keys, so you pay providers directly instead of a per-seat subscription, and your skills and chats stay in your own storage.

How do I install Composables in TypingMind?

Open Plugins → Skills → Install from GitHub in TypingMind and paste https://github.com/PatternsDev/skills/tree/main/vue/composables. TypingMind reads its SKILL.md and installs it as a skill you can enable per chat.

Which AI models can use Composables?

Any model you connect in TypingMind. AI skills are plain Markdown instructions rather than provider-specific code, so GPT, Claude, Gemini, Grok, and local models can all load this skill when a request matches it.

How many AI models can I use with Composables?

As many as you like. As long as a model supports skills, you can use Composables with it — GPT, Claude, Gemini, Grok, DeepSeek, Mistral, Llama and more — all on TypingMind with your own API keys.

Is the Composables AI skill free?

Yes. It is published on GitHub by PatternsDev under the MIT license. You only pay your own AI provider for the tokens you use.

What are AI skills?

An AI skill is a reusable instruction bundle that teaches an AI model how to do one specific task. It follows the open Agent Skills format: a SKILL.md file with a name and description, plus any scripts, templates or reference files the model may need. The model reads the instructions only when your request matches the skill, so an installed skill costs nothing until it is used.

How are AI skills different from plugins or MCP servers?

A plugin or MCP server gives a model new tools to call — code that runs somewhere and returns a result. An AI skill gives the model knowledge and process instead: how to approach a task, which steps to follow, what good output looks like. Skills are plain Markdown, so they need no server, no API key and no runtime, and they work with any model.

View all

Set up your own AI workspace now

Get notified about new features and future giveaways by subscribing to our newsletter 👇