# Common use cases

Practical recipes and patterns for working with hooks.js, based on real-world components.

## Conditional Class Generation

Build CSS class strings based on multiple properties:

```javascript
const transformHook = (rw) => {
    const {
        size,
        variant,
        isRounded,
        hasShadow,
        customClasses
    } = rw.props;
    
    const classes = [
        // Size classes
        size,
        
        // Variant styles
        variant === 'primary' && 'bg-blue-500 text-white',
        variant === 'secondary' && 'bg-gray-200 text-gray-800',
        
        // Optional modifiers
        isRounded && 'rounded-lg',
        hasShadow && 'shadow-md',
        
        // User's custom classes
        customClasses
    ]
        .filter(Boolean)
        .join(' ');
    
    rw.setProps({ classes });
};

exports.transformHook = transformHook;
```

## Edit vs Preview Mode Branching

Show different content or behavior based on the current mode:

```javascript
const transformHook = (rw) => {
    const { mode } = rw.project;
    const { sharedAssetPath } = rw.component;
    const { image, video } = rw.props;
    
    const isEditMode = mode === 'edit';
    const hasImage = image && image.image;
    
    // Show placeholder in edit mode when no image is set
    const displayImage = hasImage 
        ? image.image 
        : (isEditMode ? `${sharedAssetPath}/images/placeholder.png` : null);
    
    // Don't autoplay videos in edit mode
    const videoAutoplay = !isEditMode;
    
    // Include interactive features only in preview
    const includeInteractive = !isEditMode;
    
    rw.setProps({
        isEditMode,
        displayImage,
        hasImage,
        videoAutoplay,
        includeInteractive
    });
};

exports.transformHook = transformHook;
```

## Responsive Image Handling

Generate responsive image sources based on theme breakpoints:

```javascript
const transformHook = (rw) => {
    const { image } = rw.props;
    const { breakpoints } = rw.theme;
    const { names, screens } = breakpoints;
    
    if (!image || !image.image) {
        rw.setProps({ hasImage: false });
        return;
    }
    
    // Generate sources for each breakpoint, largest first
    const sources = names
        .filter(name => screens[name])
        .sort((a, b) => screens[b] - screens[a])
        .map(name => ({
            media: `(min-width: ${screens[name]}px)`,
            srcset: rw.resizeResource(image, screens[name] * 2), // 2x for retina
            breakpoint: name
        }));
    
    rw.setProps({
        hasImage: true,
        sources,
        fallbackSrc: rw.resizeResource(image, 800),
        alt: image.alt || ''
    });
};

exports.transformHook = transformHook;
```

Template:

```html
@if(hasImage)
<picture>
    @each(source in sources)
        <source media="{{source.media}}" srcset="{{source.srcset}}">
    @endeach
    <img src="{{fallbackSrc}}" alt="{{alt}}">
</picture>
@endif
```

## Root Element Configuration

Configure the wrapper element with dynamic tag, classes, and attributes:

```javascript
const transformHook = (rw) => {
    const { 
        customId,
        link,
        padding,
        background,
        shadow,
        htmlTag
    } = rw.props;
    const { id } = rw.node;
    
    // Determine if this should be a link
    const hasLink = link && link.href && link.href.length > 0;
    
    // Build class list
    const wrapperClasses = [
        `group/${id}`,
        padding,
        background,
        shadow
    ].filter(Boolean).join(' ');
    
    // Configure root element
    rw.setRootElement({
        as: hasLink ? 'a' : (htmlTag || 'div'),
        class: wrapperClasses,
        args: {
            id: customId || undefined,
            ...(hasLink ? {
                href: link.href,
                title: link.title,
                target: link.target
            } : {})
        }
    });
    
    // Register anchor if custom ID is set
    if (customId && customId.length > 0) {
        rw.addAnchor(customId);
    }
    
    rw.setProps({ hasLink });
};

exports.transformHook = transformHook;
```

## Collection Data Transformation

Process and enhance collection data:

```javascript
const transformHook = (rw) => {
    const { items } = rw.collections;
    
    if (!items || items.length === 0) {
        rw.setProps({ 
            hasItems: false,
            items: [] 
        });
        return;
    }
    
    // Enhance each item with computed properties
    const enhancedItems = items.map((item, index) => ({
        ...item,
        isFirst: index === 0,
        isLast: index === items.length - 1,
        index: index,
        // Generate thumbnail if item has an image
        thumbnail: item.image ? rw.resizeResource(item.image, 400) : null
    }));
    
    // Calculate aggregate data
    const totalPrice = items
        .filter(item => item.price)
        .reduce((sum, item) => sum + item.price, 0);
    
    rw.setProps({
        hasItems: true,
        items: enhancedItems,
        itemCount: items.length,
        totalPrice,
        formattedTotal: `$${totalPrice.toFixed(2)}`
    });
};

exports.transformHook = transformHook;
```

## Filter Tags for Filtering

Set up data attributes for JavaScript-based filtering:

```javascript
const transformHook = (rw) => {
    const { tags } = rw.collections;
    const { filterGroup, customGroupId } = rw.props;
    const { parent } = rw.node;
    
    // Create comma-separated tag list for data attribute
    const dataTags = tags 
        ? tags.map(tag => tag.title).join(',') 
        : '';
    
    // Determine filter group ID
    const groupId = filterGroup === 'parent' 
        ? parent.id 
        : customGroupId;
    
    rw.setRootElement({
        as: 'div',
        class: 'filter-item',
        args: {
            'data-filter-tags': dataTags,
            'data-filter-group': groupId
        }
    });
    
    rw.setProps({
        tags,
        hasTags: tags && tags.length > 0
    });
};

exports.transformHook = transformHook;
```

## Alpine.js Integration

Set up Alpine.js data and bindings:

```javascript
const transformHook = (rw) => {
    const { id } = rw.node;
    const { openOnLoad, animation } = rw.props;
    
    // Configure for accordion behavior
    const config = {
        openOnLoad: openOnLoad === 'true',
        animation: animation
    };
    
    rw.setRootElement({
        as: 'div',
        class: `group/${id}`,
        args: {
            'x-data': `accordion('${id}', ${JSON.stringify(config).replace(/"/g, "'")})`,
            'x-bind': 'details',
            'data-open': 'false',
            'role': 'group',
            'aria-roledescription': 'accordion'
        }
    });
    
    rw.setProps({
        nodeId: id,
        showContent: rw.project.mode !== 'edit' || openOnLoad === 'true'
    });
};

exports.transformHook = transformHook;
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.realmacsoftware.com/elements-docs/elements-language/component/hooks.js/common-use-cases.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
